Redis timeout error on C# but server is ok - c#

I´m getting error on my Redis server. I get timeout error but it looks like is connected and evertthing is fine.
StackExchange.Redis.RedisTimeoutException
HResult=0x80131505
Message=Timeout performing SETEX (5000ms), inst: 0, qu: 0, qs: 0, aw: False, bw: CheckingForTimeout, rs: NotStarted, ws: Initializing, in: 0, last-in: 0, cur-in: 0, sync-ops: 1, async-ops: 0, serverEndpoint: IP:PORT, conn-sec: n/a, mc: 1/1/0, mgr: 10 of 10 available, clientName: MACHINENAME(SE.Redis-v2.6.86.49666), IOCP: (Busy=1,Free=999,Min=8,Max=1000), WORKER: (Busy=1,Free=32766,Min=8,Max=32767), POOL: (Threads=12,QueuedItems=0,CompletedItems=224), v: 2.6.86.49666 (Please take a look at this article for some common client-side issues that can cause timeouts: https://stackexchange.github.io/StackExchange.Redis/Timeouts)
Source=StackExchange.Redis
StackTrace:
at StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImplT
at Dell.CorpIT.IATJobs.Infrastructure.JobContext.SetValue(String key, String value) in C:\Users\diego_ritzel\source\repos\iat-job-runner\Dell.CorpIT.IATJobs.Infarstructure\JobContext.cs:line 46
at Dell.CorpIT.IATJobs.API.Controllers.RedisController.Put(String value, String key) in C:\Users\diego_ritzel\source\repos\iat-job-runner\Dell.CorpIT.Interlock.IATJobsAPI\Controllers\RedisController.cs:line 41
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<<InvokeActionMethodAsync>g__Logged|12_1>d.MoveNext()
My connection string (credentials replaced) is:
"RedisServer": "ip:port,password=password,ssl=True,abortconnect=False,allowadmin=true,connecttimeout=10000,connectretry=5,keepalive=86400,synctimeout=5000"
My connection class:
using StackExchange.Redis;
namespace Dell.CorpIT.IATJobs.Infrastructure
{
public class JobContext
{
private readonly ConnectionMultiplexer _connection;
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
return ConnectionMultiplexer.Connect("RedisServer");
});
public static ConnectionMultiplexer Connection
{
get { return lazyConnection.Value; }
}
public JobContext(IConfiguration configuration)
{
var connectionString = configuration.GetConnectionString("RedisServer");
_connection = ConnectionMultiplexer.Connect(connectionString);
lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
return ConnectionMultiplexer.Connect(connectionString);
});
}
public string GetValueFromKey(string key)
{
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException(nameof(key));
var dbRedis = Connection.GetDatabase();
return (dbRedis.KeyExists(key))
? dbRedis.StringGet(key)
: "";
}
public void SetValue(string key, string value)
{
var dbRedis = _connection.GetDatabase();
dbRedis.StringSet(key, value,new TimeSpan(0,0,60));
}
}
}
My POC controller:
[Route("Redis")]
[HttpPut]
[AllowAnonymous]
public ActionResult Put(string value, string key)
{
var redisContext = new JobContext(_configuration);
key = (string.IsNullOrEmpty(key)) ? Guid.NewGuid().ToString() : key;
value = (string.IsNullOrEmpty(value)) ? "aaa" : value;
redisContext.SetValue(key, value);
if (redisContext.GetValueFromKey(key) == value)
{
return Ok();
} else
{
return Problem();
}
}
The same server successfully connected on RedisInsight:
I have checked a lot of places on the internet but none of them is related to this.

Related

I am using StackExhange.Redis.Extensions.Core nuget package in .net core. I want to know where exactly is the connection gets opened to Redis?

I am using StackExhange.Redis.Extensions.Core nuget package in .net core. I want to know where exactly is the connection gets opened to Redis ?
Here is my code :
Here is me appsettings : enter code here
"Redis": {
"Password": "xyz123",
"AllowAdmin": true,
"Ssl": true,
"KeepAlive": 180,
"ConnectTimeout": 5000, //Timeout for connecting to redis
"ConnectRetry": 2,
"PoolSize": 1,
"User": "appuser",
"SyncTimeout": 5000,
"AsyncTimeout": 5000,
"Database": 0,
"Hosts": [
{
"Host": "cluster.payment-redis.hshwxw12.use1.cache.amazonaws.com",
"Port": "6379"
}
]
}
var redisConfiguration = Configuration.GetSection("Redis").Get<RedisConfiguration>();
services.AddStackExchangeRedisExtensions(redisConfiguration);
private readonly IRedisClient _redisClient;
private readonly ILogger<ICacheService> _logger;
private IRedisDatabase _redisDatabase;
private bool IsDisposed = false;
public CacheService(IRedisClient redisClient, ILogger<ICacheService> _logger)
{
this._redisClient = redisClient;
this._logger = _logger;
}
private IRedisDatabase Database
{
get
{
if (_redisDatabase == null)
{
_logger.LogInformation(_redisClient.ToString());
_redisDatabase = _redisClient.GetDefaultDatabase();
}
return _redisDatabase;
}
}
public async Task<(bool isSuccess, string errorMessage)> SetAsync<T>(string key, T data, TimeSpan? expiry)
{
bool isSuccess = false;
string errorMessage = string.Empty;
if (expiry == null)
{
expiry = TimeSpan.FromHours(1);
}
try
{
string jsonData = JsonConvert.SerializeObject(data);
await Database.AddAsync(key, jsonData, (TimeSpan)expiry).ConfigureAwait(false);
isSuccess = true;
}
catch (Exception ex)
{
errorMessage = ex?.Message;
_logger.LogError(ex?.Message);
}
return (isSuccess, errorMessage);
}
Redis connection will open in the below condition.
await Database.AddAsync(key, jsonData, (TimeSpan)expiry).ConfigureAwait(false);

Requests are timing-out when light payload is applied to .Net Core Web Api

I have an API which basically receives a request and pushes it to an SQS queue, nothing complicated.
[HttpPost]
public ActionResult Post([FromBody]object message, [FromHeader] string source)
{
if (message== null)
return new UnsupportedMediaTypeResult();
if (PublishMessageToSQS(JsonConvert.SerializeObject(message),source))
return StatusCode(201);
return StatusCode(500);
}
private bool PublishMessage(string message, string source)
{
try
{
RetryWhenException.Do(
() =>
{
SendMessageRequest request = new SendMessageRequest()
{
MessageBody = message,
MessageAttributes = new Dictionary<string, MessageAttributeValue>(),
QueueUrl = "my queue",
};
if (!string.IsNullOrEmpty(source))
request.MessageAttributes.Add("source", new MessageAttributeValue()
{
StringValue = source,
DataType = "String"
});
var result = sqsClient.SendMessageAsync(request).Result;
}, 3, 1000);
return true;
}
catch (Exception e)
{
//log
throw;
}
}
This API is containerized and deployed to AWS ECS on low resources machine (0.25 VCpu, 512 MB RAM).
When applying a light load on the API (10 requests per second), requests start to timeout after a while.
I stopped receiving timeouts when applying one of:
1- Use more resources (2 VCPU, 4GB RAM)
2- make my action async.
[HttpPost]
public async Task<ActionResult> Post([FromBody]object message, [FromHeader] string source)
{
if (message== null)
return new UnsupportedMediaTypeResult();
if (await PublishMessageToSQS(JsonConvert.SerializeObject(message), source))
return StatusCode(201);
return StatusCode(500);
}
private async Task<bool> PublishMessage(string message, string source)
{
try
{
await RetryWhenException.Do(
async () =>
{
SendMessageRequest request = new SendMessageRequest()
{
MessageBody = message,
MessageAttributes = new Dictionary<string, MessageAttributeValue>(),
QueueUrl = "my queue",
};
if (!string.IsNullOrEmpty(source))
request.MessageAttributes.Add("source", new MessageAttributeValue()
{
StringValue = source,
DataType = "String"
});
var result = await sqsClient.SendMessageAsync(request);
}, 3, 1000);
return true;
}
catch (Exception e)
{
//log
throw;
}
}
RetryWhenException code:
public static class RetryWhenException
{
public static void Do(Action action, int maxAttemptCount = 3, int retryInterval = 1000)
{
var exceptions = new List<Exception>();
for (var attempted = 0; attempted < maxAttemptCount; attempted++)
{
try
{
if (attempted > 0)
{
Thread.Sleep(retryInterval);
}
action();
return;
}
catch (Exception ex)
{
exceptions.Add(ex);
}
}
throw new AggregateException(exceptions);
}
}
I know that Async frees threads, but pushing to SQS is not that costy and the number of requests is not that high.
I really don't understand why I was getting timeouts when applying such low payload, and why async did the trick, any explanation?

NSubstitute.Exceptions.ReceivedCallsException: Expected to receive a call matching error while unit testing

I am getting a below error while unit testing the piece of code
NSubstitute.Exceptions.ReceivedCallsException: Expected to receive a call matching error while unit testing
NSubstitute.Exceptions.ReceivedCallsException
HResult=0x80131500
Message=Expected to receive a call matching:
enrollWithHelper("", "")
Actually received no matching calls.
Source=NSubstitute
StackTrace:
at NSubstitute.Core.ReceivedCallsExceptionThrower.Throw(ICallSpecification callSpecification, IEnumerable1 matchingCalls, IEnumerable1 nonMatchingCalls, Quantity requiredQuantity)
at NSubstitute.Routing.Handlers.CheckReceivedCallsHandler.Handle(ICall call)
at NSubstitute.Routing.Route.Handle(ICall call)
at NSubstitute.Proxies.CastleDynamicProxy.CastleForwardingInterceptor.Intercept(IInvocation invocation)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.ObjectProxy_1.enrollWithHelper(String name, String type)
at MyProject.MyTest.processing_test_pass() in C:\MyProject\MyTest.cs:line 75
Framework: .NET Core
Unit Testing: NSubstitute
Here is my class under test
public class MyService: IMysService
{
private readonly IRepository _repository;
Private readonly IIoTHelper _iotHelper;
Private readonly HttpClient _httpClient;
private Configuration _configuration;
public MyService(IRepository repository, IIoTHelper iotHelper, HttpClient httpClient )
{
_repository = repository;
_iotHelper =iotHelper;
_httpClient = httpClient ;
}
public bool CallService(JObject reqObj, out Status status)
{
bool provisioningSuccess = false;
return PreProcessing(reqObj,out Status status); //private method
}
}
Here is my private method
private PreProcessing(JObject JosnObj, out Status status)
{
if (_configuration== null)
{
_configuration= _repository.GetConfigurations()
}
using (var client = this._httpClient)
{
var request = new {_configuration.Number,_configuration.Type};
var response = client.PostAsJsonAsync("api/preprocess", request).Result;
if (response.IsSuccessStatusCode)
{
_iotHelper.enrollWithHelper(_configuration.Number,_configuration.Type);
}
}
}
Here is my Configuration class
public class Configuration
{
public Configuration (string number, string type)
{
Number= number;
Type= type;
}
public string Number { get;}
public string Type { get; }
}
Here is my unit test code, where I want to make sure it reaches the private method
protected override void InitializeTest()
{
this._repository = Substitute.For<IRepository>();
this._iotHelper = Substitute.For<IIotHelper>();
}
[TestMethod]
public void processing_test_pass()
{
//Arrange
var messageHandler = new MockHttpMessageHandler("TEST VALUE", HttpStatusCode.OK);
var httpClient = new HttpClient(messageHandler);
JObject reqobj= new JObject(
new JProperty("user", "username"),
new JProperty("pass", "password"));
Status status = new Status();
//act
var t = new MyService(this._repository,this._iotHelper, httpClient );
bool success = t.CallService(reqobj, out status);
//assert
this._iotHelper.Received().enrollWithHelper("","");
}
How would I test enrollWithHelper is called?
Also I am stuck due to error!

SemaphoreSlim to protect the connection pool from exhaustion

I have a microservice (Web API) within an eventdriven architecture receiving messages from RabbitMQ and it is supposed to save them into a PostgreSQL DB using ADO.NET.
Unfortunately, my connection pool (currently set to 50) gets exhausted quite fast, giving me this error message:
The connection pool has been exhausted, either raise MaxPoolSize
My RabbitMQ Consumer is set up like this (Singleton):
public class Listener : RabbitMqConnection
{
public AsyncEventingBasicConsumer _asyncConsumer;
private static readonly SemaphoreSlim AsyncLock = new SemaphoreSlim(1, 1);
public Listener()
{
_asyncConsumer = new AsyncEventingBasicConsumer(_channel);
_asyncConsumer.Received += ConsumerReceived;
}
public async Task ConsumerReceived(object sender, BasicDeliverEventArgs message)
{
await AsyncLock.WaitAsync();
try
{
//Performing logic and saving into database
//....
using (var ctx = ContextFactory.GetContext<PostgreSqlDatabaseContext>(_connectionString))
{
//Creating query with StringBuilder...
await ctx.Database.ExecuteSqlCommandAsync(query.ToString(), parameters);
}
_channel.BasicAck(message.DeliveryTag, false);
}
catch (DecoderFallbackException decoderFallbackException)
{
_logger.LogError($"...");
_channel.BasicNack(message.DeliveryTag, false, false);
}
finally {
AsyncLock.Release();
}
}
}
ContextFactory
internal class ContextFactory
{
public static T GetContext<T>(string sqlConnection) where T : DbContext
{
var optionsBuilder = new DbContextOptionsBuilder<PostgreSqlDatabaseContext>();
optionsBuilder.UseNpgsql(sqlConnection);
return new PostgreSqlDatabaseContext(optionsBuilder.Options) as T;
}
}
RabbitMqConnection:
public abstract class RabbitMQConnection
{
public IModel _channel;
public IBasicProperties _properties;
public AsyncEventingBasicConsumer _asyncConsumer;
public ConnectionFactory _factory;
public ConnectConfiguration _connectConfiguration;
bool isConnected = false;
public void Connect(ConnectConfiguration connectConfiguration)
{
if (!isConnected)
{
_connectConfiguration = connectConfiguration;
CreateFactory(_connectConfiguration);
SetupConfiguration(_connectConfiguration.Exchange);
}
}
private void CreateFactory(ConnectConfiguration config)
{
_factory = new ConnectionFactory
{
AutomaticRecoveryEnabled = true,
DispatchConsumersAsync = true,
UseBackgroundThreadsForIO = true,
RequestedHeartbeat = 15,
HostName = config.Server,
UserName = config.UserName,
Password = config.Password
};
if (!string.IsNullOrWhiteSpace(config.Vhost))
_factory.VirtualHost = config.Vhost;
}
private void SetupConfiguration(string exchange)
{
var connection = _factory.CreateConnection();
_channel = connection.CreateModel();
_properties = _channel.CreateBasicProperties();
_properties.Persistent = true;
_channel.BasicQos(0, 10, false);
_channel.ExchangeDeclare(exchange, "topic", true);
isConnected = true;
}
}
I can´t not understand why I keep getting this error. Isn´t the SemaphoreSlim with WaitAsync() and Release() suppose to prevent the ConsumerReceived method from running the logic?

how to execute huge rest based url in wcf data services?

I'm using Wcf data service(V3). From IOS App they will send Signature through URL. Problem is sometimes user enters long signature in that situation it is giving an error like "Url is too long". how can i fix this issue on wcf data services.
Advance Thanks.
If the message client want to give to service is large, it is recommended to use POST.
You can find the guide for Actions in WCF Data Service V3 here:
http://blogs.msdn.com/b/odatateam/archive/2011/10/17/actions-in-wcf-data-services.aspx
And here is quick demo for setting up a WCF DS service with Action support:
public class Service : DataService<Context>, IServiceProvider
{
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetServiceActionAccessRule("*", ServiceActionRights.Invoke);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
public object GetService(Type serviceType)
{
return typeof(IDataServiceActionProvider) == serviceType ? new ActionProvider() : null;
}
}
public class ActionProvider : IDataServiceActionProvider, IDataServiceActionResolver
{
private static List<ServiceAction> actions;
static ActionProvider()
{
ServiceAction movieRateAction = new ServiceAction(
"Action1", // name of the action
ResourceType.GetPrimitiveResourceType(typeof(string)), // no return type i.e. void
null, // no return type means we don’t need to know the ResourceSet so use null.
OperationParameterBindingKind.Never,
new ServiceActionParameter[] {
new ServiceActionParameter("val", ResourceType.GetPrimitiveResourceType(typeof(string)))
}
);
movieRateAction.SetReadOnly();
actions = new List<ServiceAction>() { movieRateAction };
}
public IEnumerable<ServiceAction> GetServiceActions(DataServiceOperationContext operationContext)
{
return actions;
}
public bool TryResolveServiceAction(DataServiceOperationContext operationContext, string serviceActionName,
out ServiceAction serviceAction)
{
serviceAction = null;
return false;
}
public IEnumerable<ServiceAction> GetServiceActionsByBindingParameterType(DataServiceOperationContext operationContext,
ResourceType bindingParameterType)
{
return Enumerable.Empty<ServiceAction>();
}
public IDataServiceInvokable CreateInvokable(DataServiceOperationContext operationContext, ServiceAction serviceAction,
object[] parameterTokens)
{
return new DataServiceInvokable(parameterTokens);
}
public bool AdvertiseServiceAction(DataServiceOperationContext operationContext, ServiceAction serviceAction, object resourceInstance, bool resourceInstanceInFeed, ref ODataAction actionToSerialize)
{
actionToSerialize = null;
return false;
}
public bool TryResolveServiceAction(DataServiceOperationContext operationContext, ServiceActionResolverArgs resolverArgs, out ServiceAction serviceAction)
{
serviceAction = actions[0];
return true;
}
}
public class DataServiceInvokable : IDataServiceInvokable
{
private readonly object[] parameters;
private string result;
public DataServiceInvokable(object[] parameters)
{
this.parameters = parameters;
}
public object GetResult()
{
return result;
}
public void Invoke()
{
result = parameters[0] as string;
}
}
Then you could send a POST request to http://example.org/service.svc/Action1
Header:
Content-Type: Application/json
Request Body:
{"val":"MessageToPostHere..."}
If you are using .Net 4.0 or above, you could experiment with your web.config settings file, with this:
<system.web>
...
<httpRuntime maxUrlLength="500" />
....
</system.web>

Categories

Resources