Implement Redis Cache in place of In Memory Cache? - asynchronous

I have a InMemory Cache method which I want to implement using Redis Cache, it uses the concept of Semaphore in the InMemory Cache, hence I have gone through many documentation's like the Redis documentation on Distributed Locking, and tried using different locking mechanisms in Redis such as RedLock.Net , RedLock-cs etc, but I haven't been able to completely go through with the technique, as even though I am able to recreate the method, but the running time for large number of processes for it in Redis is coming out to be huge.
The code that I am trying to recreate is as follows:
private readonly ConcurrentDictionary<string, Lazy<SemaphoreSlim>> _semaphores = new ConcurrentDictionary<string, Lazy<SemaphoreSlim>>();
public async ValueTask<TValue> GetMethod<TValue>(string key,Func<Task<TValue>> get,int time)
{
return await SemaphoreMethod(key, async() =>
{
var value = await get();
if(value != null)
cache.set(key,value,time);
return value;
});
}
private async ValueTask<TValue> SemaphoreMethod<TValue>(string key,Func<Task<TValue>> get)
{
if(cache.TryGetValue(key,out TValue result))
return result;
var semaphore = _semaphores.GetOrAdd(key,k => new Lazy<SemaphoreSlim>(() => new SemaphoreSlim(1,1))).Value;
await semaphore.WaitAsync();
TValue answer = default;
if(cache.TryGetValue(key,out TValue result2))
return result2;
answer = await get();
_semaphores.TryRemove(key,out _);
semaphore.Release();
return answer;
}
And the method which I run against it to check it's implementation and efficiency in comparison to InMemory Cache is as follows:
public async Task GetValueAsync_Tasks()
{
var callCount = 0;
async Task<string> Get()
{
Interlocked.Increment(ref callCount);
return "value";
}
const int count = 1000;
var valueTasks = new List<ValueTask<string>>(count);
for(var i=0;i<count;i++)
valueTask.Add(GetMethod("key",Get));
var tasks = valueTasks.Select(vt => vt.AsTask()).ToArray();
Task.WaitAll(tasks);
callCount.Should().Be(1);
}
One other thing that I am not able to understand that in which part of the test method, would the code run all the tasks created, i.e. in this one
valueTasks.Add(sut.GetValueAsync("key", FetchValue));
or in this one
Task.WaitAll(tasks);
I am using the StackExchange.Redis library, and Azure Cache for Redis for storing the respective data.

Related

Cannot use CancellationToken to end orchestrator function

I am using an orchestration to await two sub-orchestrations which are executing in parallel or a timeout of 5min, whatever comes first. I am passing a CancellationToken to the sub-orchestrators and therein throw on cancellation using token.ThrowIfCancellationRequested(). Also, since I have created a timer in the main orchestrator function, I am responsible to clear it in the case the timeout is not triggered itself. This is documented here.
main orchestrator:
public class Fxbm_workflow
{
[FunctionName(nameof(Fxbm_workflow))]
public async Task Run([OrchestrationTrigger] IDurableOrchestrationContext ctx, ILogger log)
{
log = ctx.CreateReplaySafeLogger(log);
var parentWorkflowId = ctx.InstanceId;
var trigger = ctx.GetInput<Trigger<OrchestrationInput2>>();
using var cts = new CancellationTokenSource();
var expireIn = ctx.CurrentUtcDateTime.AddMinutes(5);
var responseTasks = new [] {327, 41}.Select(id => {
var input = (id, cts.Token);
var childWorkflowId = $"{parentWorkflowId}_{nameof(Fxbm_receive_response_workflow)}_{id}";
return ctx.CallSubOrchestratorAsync<object>(nameof(Fxbm_receive_response_workflow), instanceId: childWorkflowId, input: input);
});
var timeoutTask = ctx.CreateTimer(expireIn, cts.Token);
// await tasks, choose winner
var winner = await Task.WhenAny(Task.WhenAll(responseTasks), timeoutTask);
if (winner == timeoutTask)
{
log.LogWarning("winner= timeout");
// no need to cts.Cancel() here
}
else
{
log.LogWarning("winner= all tasks have finished before the timeout");
cts.Cancel();
}
}
}
sub-orchestrator function:
public class Fxbm_receive_response_workflow
{
[FunctionName(nameof(Fxbm_receive_response_workflow))]
public async Task<object> Run([OrchestrationTrigger] IDurableOrchestrationContext ctx, ILogger log)
{
log = ctx.CreateReplaySafeLogger(log);
var (clientId, token) = ctx.GetInput<(int, CancellationToken)>();
token.ThrowIfCancellationRequested();
log.LogWarning($"waiting for response of clientId= {clientId}");
var evnt = await ctx.WaitForExternalEvent<object>(name: clientId.ToString());
log.LogWarning($"response received for clientId= {clientId}");
await ctx.CallActivityAsync(nameof(Fxbm_notifyOfNewReport), evnt);
return evnt;
}
}
However, this doesn't work. In the screenshot below there's the execution history extracted using DfMon. One of the two sub-orchestrations completes successfully. Before the other one can finish, the 5min timeout is triggered. Still, neither does the remaining sub-orchestration fail (due to token.ThrowIfCancellationRequested()), nor does the parent orchestration complete, inspite of calling cts.Cancel(). Both are still in a Running state.
It is my understanding the sub-orchestration should have failed/thrown and the parent orchestration should have concluded successfully. Does someone know why this is not the case here? Since orchestrator functions are re-executed again and again until finished, I do worry about unncessary $$$ cost of this when deployed in Azure.

Issues with async / await in C#

I'm using async / await methods in C#... my operations are to create databases on Azure Cosmos DB, the problem is when the code is runnnig, for any reason... the flow brakes without any issues apparently
can anyone help?
Task p= Run();
public async static Task Run()
{
.
.
.
await CreateDatabase(client)
}
private async static Task CreateDatabase(DocumentClient client)
{
var databaseDefinition = new Database { Id = "MyDB" };
var result = await client.CreateDatabaseAsync(databaseDefinition);
var database = result.Resource;
}
//In second line, the code brake when the debugging is operating
//==> var result = await client.CreateDatabaseAsync(databaseDefinition);

Hot to get count of connection in SignalR Core Group

How can I get count of connections in specific SignalR Core group?
Something like that:
this.Clients.Group("Something").Count();
It would be also good if SendAsync would return how many clients send message:
var count = await this.Clients.Client(this.Context.ConnectionId).SendAsync("msg", msg);
I need this to determine if group is empty. Data should be correct if user disconnects from SignalR Core with force (unplug net cable)...
You can use the OnConnected and OnDisconnected Events and save the connection / connectionIds.
I use something like this with additional informations:
internal static ConcurrentDictionary<string, ConnectionInfos> Users = new ConcurrentDictionary<string, ConnectionInfos>();
public override async Task OnConnectedAsync()
{
var connId = Context.ConnectionId;
if (!Users.Keys.Any(x => x == connId))
{
Users.TryAdd(connId, new ConnectionInfos { /*...*/});
}
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception exception)
{
var id = Context.ConnectionId;
if (Users.TryRemove(id, out ConnectionInfos ci))
{
//Connection removed
}
await base.OnDisconnectedAsync(exception);
}

Error calling HttpClient.GetAsync: The underlying connection was closed

I have an asp.net MVC website which is consuming a rest api to receive it's data. I'm using asynchronous tasks to perform the requests as there can be many on each page. After a while of uptime the website has been throwing the following error when trying to receive data.
The underlying connection was closed: An unexpected error occurred on a send.
I read that this could be due to the maxconnection settings on the web.config but increasing this doesn't seem to make much difference.
I'm also using caching to reduce the load on the api. The task is cached so the result can be used later.
The only way I've found to fix this is by recycling the application pool. Any help would be appreciated.
/* Code from page_load */
var currenciesTask = ApiClient.GetAsync<CurrencyListWrapper>("currencies");
var blogArticleTask = ApiClient.GetAsync<BlogArticleListWrapper>("blog/articles", "limit=10");
var seoPageTask = ApiClient.GetAsync<SEOPageListWrapper>("seopages");
await Task.WhenAll(currenciesTask, blogArticleTask, seoPageTask);
/* Code from data access later */
public class ApiClient : HttpClient
{
public static Task<T> GetAsync<T>(string operation, string query = null, bool cache = true)
{
// Check if task is in cache
string cacheName = null;
if (cache)
{
cacheName = String.Format("{0}_{1}_{2}", operation, query ?? String.Empty, App.GetLanguage());
var cachedTask = HttpRuntime.Cache[cacheName];
if (cachedTask != null)
{
return (Task<T>)cachedTask;
}
}
// Get data task
var task = GetAsyncData<T>(operation, query);
// Add to cache if required
if (task != null && cache)
{
App.AddToCache(cacheName, task);
}
return task;
}
public static async Task<T> GetAsyncData<T>(string operation, string query = null)
{
using (ApiClient client = new ApiClient())
{
string url;
if (query != null)
{
url = String.Format("{0}?{1}", operation, query);
}
else
{
url = String.Format("{0}", operation);
}
var response = await client.GetAsync(url);
return (await response.Content.ReadAsAsync<T>());
}
}
}
This is wrong,
The task is cached so the result can be used later.
You are supposed to cache result, not the task. At end of first execution, your HttpClient is closed and when you try to retrieve cached task, it will not work.
public class ApiClient : HttpClient
{
public static async Task<T> GetAsync<T>(string operation, string query = null, bool cache = true)
{
// Check if task is in cache
string cacheName = null;
if (cache)
{
cacheName = String.Format("{0}_{1}_{2}", operation, query ?? String.Empty, App.GetLanguage());
T cachedResult = (T)HttpRuntime.Cache[cacheName];
if (cachedResult!= null)
{
return Task.FromResult(cachedResult);
}
}
// Get data task
var result = await GetAsyncData<T>(operation, query);
// Add to cache if required
if (result != null && cache)
{
App.AddToCache(cacheName, result);
}
return result;
}
public static async Task<T> GetAsyncData<T>(string operation, string query = null)
{
using (ApiClient client = new ApiClient())
{
string url;
if (query != null)
{
url = String.Format("{0}?{1}", operation, query);
}
else
{
url = String.Format("{0}", operation);
}
var response = await client.GetAsync(url);
return (await response.Content.ReadAsAsync<T>());
}
}
}
Akash could be right.
But it seems more or less connection issue with application pool. Set the connection limit 0 to make it unlimited at application pool.
Have a finally block in you code, and
gc.collect();
garbage collection method to be called to remove unused connections to make space for other connection.

Preserve HttpContext when going async with WebAPI (Medium Trust)

I am building a set of ASP.Net hosted WebAPI services that must use an old library which depends heavily on HttpContext.Current. I am having trouble ensuring that context is preserved in all the methods that participate in an async call. I have tried several variations with await/Task.Wait and TaskScheduler.FromCurrentSynchronizationContext() on the below code.
[HttpGet]
public Task<IEnumerable<string>> ContinueWith()
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR"); //or another culture that is not the default on your machine
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
var output = new List<string> { TestOutput("Action start") };
var task = Task.Factory.StartNew(() =>
{
Thread.Sleep(1000);
return TestOutput("In Task");
}).ContinueWith(slowString =>
{
output.Add(slowString.Result);
output.Add(TestOutput("Action end"));
return output as IEnumerable<string>;
});
output.Add(TestOutput("Action Mid"));
return task;
}
private string TestOutput(string label)
{
var s = label + " ThreadID: " + Thread.CurrentThread.ManagedThreadId.ToString(CultureInfo.InvariantCulture);
s += " " + Thread.CurrentThread.CurrentCulture.EnglishName;
s += HttpContext.Current == null ? " No Context" : " Has Context";
Debug.WriteLine(s);
return s;
}
I would like to be able to ensure that the CurrentCulture is fr-FR, and that HttpContext.Current is not null at each point where TestOutput is called. I have not succeeded in doing that for the "In Task" call with anything I have tried. Also in some of my test thread id never varies suggesting that I have effectively removed the asynchronicity of the method. How can I ensure that the culture and HttpContext.Current are preserved at each call to TestOutput, and that the code is free to run on different threads?
Capturing HttpContext.Current in a closure and then simply setting it again will not work for me as I need to support Medium Trust which will throw a security exception when calling the HttpContext.Current setter.
A little noticed fact, HttpContext.Current is writable.
var context = HttpContext.Current;
var task = Task.Factory.StartNew(() => {
HttpContext.Current = context;
// You may want to set CultureInformation here too.
return TestOutput("In Task");
});
Context is preserved whenever you await tasks.
What you're seeing is that there's no context for thread pool tasks (Task.Run, TaskFactory.StartNew, or for that matter BackgroundWorker or Thread or Delegate.BeginInvoke). This is normal and expected.
So, don't use a thread pool task. Your example code seems to want to do parallel processing with multiple threads having the HttpContext, which simply isn't possible.
You can do concurrent async methods if you want, but this requires that your Thread.Sleep can actually be an async method instead of a CPU-based method:
[HttpGet]
public async Task<IEnumerable<string>> Test()
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
var output = new List<string> { TestOutput("Action start") };
var task = SlowStringAsync();
output.Add(TestOutput("Action Mid"));
output.Add(await task);
output.Add(TestOutput("Action end"));
return output;
}
public async Task<string> SlowStringAsync()
{
await Task.Delay(1000);
return TestOutput("In Task");
}
If your old library is out of your control and you can't make it async, then you'll have to call it synchronously. It's acceptable to call a synchronous method from an async method in situations like this:
[HttpGet]
public async Task<IEnumerable<string>> Test()
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
var output = new List<string> { TestOutput("Action start") };
output.Add(TestOutput("Action Mid"));
Thread.Sleep(1000);
output.Add(TestOutput("Not Really In Task"));
output.Add(TestOutput("Action end"));
return output;
}

Resources