What is the best way for exiting a loop inside an actor? - akka.net

A rendering actor is drawing a large amount of shapes onto a bitmap. I'd like to stop this process from a supervisor actor
object. Neither Kill, nor Stop do the job as they wait for the message being handled to finish. To Ask an actor from an actor seems to be advised against. What is the right approach in this situation?

When using an async method, that should be cancelable, you'd normally use a CancellationToken. If you already received an cancellation token into your method and you're going to call another async method that should be cancelled by another constraint you can setup your own CancellationTokenSource, merge the incoming token into it and forward the new token to the inner function.
If you then need to cancel the inner function, you call the .Cancel() method of your token source and your inner function must be polite enough to regulary check the state of the incoming token.
A rough sketch of this approach would be something like this:
public async Task DoSomething(CancellationToken cancellationToken)
{
var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
var token = tokenSource.Token;
var task = WorkHard(token);
task.Start();
await Task.Delay(1000);
tokenSource.Cancel();
}
private async Task WorkHard(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
Console.WriteLine("Make some hard work");
await Task.Delay(100);
}
}
A more elaborated example can be found at https://learn.microsoft.com/en-us/dotnet/standard/threading/how-to-listen-for-multiple-cancellation-requests.

Related

How to guard against double trigger of async method in Blazor wasm

I'm developing a blazor wasm application. I'm struggling with an async issue - that I find difficult to tackle, as the threading in the browser is not completely clear to me. I'm not using any async voids - everything is async Task.
From an API call (async) I get back two objects. One object I dispatch as an synchronous update to the fluxor store, and the other I have to do a async call on the local Indexdb, after which this one also enters the fluxor store.
The two fluxor store updates trigger via an event an update method of the view model. This update method is async, as it also get's some info from the IndexedDb. This async method fetches async some items from Indexdb, clears a dictionary, then enumerates over a property of the fluxor store to update the model.
This method get's called twice in quick succession, and as a result, starts interweaving.
The trouble is the first method call is paused during the enumeration over the state, next the second method call clears the dictionary, and starts it's own enumeration (and finishes), after which the first method resumes midst it's earlier started enumeration.
This results in errors - trying to add identical keys twice to the dictionary.
How can I guard against this?
How can I prevent the same method call to interweave with itself in Blazor wasm?
How can the (synchronous) enumeration part of the async update method be paused, allowing the full method to run, and next resuming the first call again?
public partial class DebugPage : BasePage, IDisposable
{
[Inject] IState<MonthBalanceState> MonthBalanceState { get; set; }
private Dictionary<IMonthBalanceAddress, int> DbCountDictionary = new Dictionary<IMonthBalanceAddress, int>();
protected override async Task OnParametersSetAsync()
{
MonthBalanceState.StateChanged += async (_, _) => await MonthBalanceState_StateChanged();
Console.WriteLine($"Linkage made to Monthbalance State");
await base.OnParametersSetAsync();
}
//This method get's called twice quickly - starting the interweaving
private async Task MonthBalanceState_StateChanged()
{
Console.WriteLine($"Update via Statechanged Monthbalance State");
var result = await UpdateDictionaryAsync();
}
private async Task<bool> UpdateDictionaryAsync()
{
DbCountDictionary.Clear();
Log.Debug("Debug dictionary updated");
foreach (IMonthBalanceLoadable mb in MonthBalanceState.Value.MonthBalances.ToList())
{
Console.WriteLine($"Adding {mb.Address.ToString()}");
DbCountDictionary.Add(mb.Address, await Db.GetCountByAddress(mb.Address));
}
return true;
}
+= async (_, _) => await MonthBalanceState_StateChanged();
This lambda is an async void wrapping your handler.
So the whole is not awaited and that is the source of your problem.
That StateChanged event should probably be an EventCallback property. Post the relevant code if you need more help.
If possible, you could use OnAfterRenderAsync(bool firstRender) instead if OnParametersSetAsync() and then only set you variables if it is the first render.

FindAsync never comes back however Find works just fine

I am using FluentValidation to validate the objects. I am simply checking checking whether the user exists in database or not. In my case, DbContext.Entity.Find works just fine but DbContext.Entity.FindAsync never returns.
Please refer to the below source code where it is happening.
public class ChangeStatusOfUserCommandValidator : AbstractValidator<ChangeStatusOfUserCommand>
{
private readonly FieldSellDbContext dbContext;
private ChangeStatusOfUserCommandValidator()
{ }
public ChangeStatusOfUserCommandValidator(FieldSellDbContext databaseContext)
{
dbContext = databaseContext;
RuleFor(u => u.UserId).NotEmpty();
RuleFor(u => u.UserId).MustAsync(UserExists).WithMessage("Provided user id already exists in the database.");
}
public async Task<bool> UserExists(int value, CancellationToken cancellationToken)
{
var user = await dbContext.Users.FindAsync(value, cancellationToken);
//var user = dbContext.Users.Find(value); --Works fine even in async method
return user != null;
}
}
Thanks
Your problem is almost certainly further up your call stack, where the code is calling Task<T>.Result, Task.Wait(), Task.GetAwaiter().GetResult(), or some similar blocking method. If your code blocks on asynchronous code in a single-threaded context (e.g., on a UI thread), it can deadlock.
The proper solution is to use async all the way; that is, use await instead of blocking on asynchronous code. Fluent validation has an asynchronous workflow (e.g., ValidateAsync, MustAsync), so you'll need to be sure to use that rather than the synchronous APIs.

Async and Await Action methods.Not working asynchronously. Don't know the reason?

I am using async action methods:
public async Task<JsonResult> SetMaterialRequisitionNoteStatus(List<Guid> ids, string statusName, Guid statusId)
{
string resp = string.Empty;
resp = await note.GeneratePartLifeNotifications_ORN(repairNote, "Outsourced Repair Note " + statusName);
if (responce.ToLower() != "ok")
{
responce = responce.Replace("Workorder", "Outsource repair note");
sendNotification(responce);
}
Utilities.SaveEntityInstance(note);
......
}
But my code is not working asynchronously. The line next to await calls wait until we get the result from GeneratePartLifeNotifications_ORN method.
It is working as same synchronous code.
I want asynchronous behaviour.
The line next to await calls wait until we get the result from
generatePartLifeNotifications_ORN method.
Well, what did you expect? await will execute that method asynchronously and will release the current thread for doing work somewhere else. When that asynchronous task is completed, the thread will comeback to pick the function execution from there with the result (unless you specify .ConfigureAwait(false), then any thread could pick the execution).
"Await" means something like "wait for", so the execution is waiting for that method to complete, but the thread left to work in something else and it is not waiting.
If you executed this in a synchronous fashion, the execution order will be the same, but the calling thread will be blocked waiting for GeneratePartLifeNotifications_ORN to finish. The magic of async, is to allow threads to working in something else instead of waiting for things that are happening away (like a webservice, or a database).
Cheers.

async method does not continue when await statement returns

I'm using MVC 4 and I have the following code :
public void DoWork(string connectionId)
{
connectionId = this.connectionId;
var a = MakeADelayAsync();
}
public async Task MakeADelayAsync()
{
await Task.Delay(5000);
var generalHubContext = GlobalHost.ConnectionManager.GetHubContext<GeneralHub>();
generalHubContext.Clients.Client(connectionId).showNotification("Completed");
}
"DoWork" method is my mvc action. what I intent to do is when the action button is pressed the "DoWork" calls an async method and returns to the client immediately. when the async method has completed his job it will notify client using signalR.
The problem is in the "MakeADelayAsync" method, those two lines after await won't be called ever. It seems that the flow never continues after await.
First question is Where is the problem in "MakeADelayAsync" ?
Second question is why do I have to write a useless code of var a = MakeADelayAsync(); to avoid compiler warning while I'm completely aware of what I am doing? I never use "a" anyway.
"DoWork" method is my mvc action. what I intent to do is when the action button is pressed the "DoWork" calls an async method and returns to the client immediately. when the async method has completed his job it will notify client using signalR.
Doing this is extremely dangerous. I strongly recommend that you use a persistent queue, as I said in my previous answer: Azure queue, MSMQ, WebSphere MQ, etc.
However, if you insist on doing it the dangerous way, then you can use the code that I have on my blog to execute background work on ASP.NET outside of a request context:
public void DoWork(string connectionId)
{
connectionId = this.connectionId;
// This is extremely dangerous code! If ASP.NET unloads
// your app, then MakeADelayAsync may not run to completion.
BackgroundTaskManager.Run(() => MakeADelayAsync());
}
First question is Where is the problem in "MakeADelayAsync" ?
You're executing code that is attempting to resume on the request context after the request is completed and the request context is disposed. It's the same problem you had before.
Second question is why do I have to write a useless code of var a = MakeADelayAsync(); to avoid compiler warning while I'm completely aware of what I am doing?
The compiler warning is telling you that the code is almost certainly a mistake... and the compiler is right.
can you try to mark your DoWork method as async?
public async void DoWork(string connectionId)
{
connectionId = this.connectionId;
var a = MakeADelayAsync();
}

Async WCF Service with multiple async calls inside

I have a web service in WCF that consume some external web services, so what I want to do is make this service asynchronous in order to release the thread, wait for the completion of all the external services, and then return the result to the client.
With Framework 4.0
public class MyService : IMyService
{
public IAsyncResult BeginDoWork(int count, AsyncCallback callback, object serviceState)
{
var proxyOne = new Gateway.BackendOperation.BackendOperationOneSoapClient();
var proxyTwo = new Gateway.BackendOperationTwo.OperationTwoSoapClient();
var taskOne = Task<int>.Factory.FromAsync(proxyOne.BeginGetNumber, proxyOne.EndGetNumber, 10, serviceState);
var taskTwo = Task<int>.Factory.FromAsync(proxyTwo.BeginGetNumber, proxyTwo.EndGetNumber, 10, serviceState);
var tasks = new Queue<Task<int>>();
tasks.Enqueue(taskOne);
tasks.Enqueue(taskTwo);
return Task.Factory.ContinueWhenAll(tasks.ToArray(), innerTasks =>
{
var tcs = new TaskCompletionSource<int>(serviceState);
int sum = 0;
foreach (var innerTask in innerTasks)
{
if (innerTask.IsFaulted)
{
tcs.SetException(innerTask.Exception);
callback(tcs.Task);
return;
}
if (innerTask.IsCompleted)
{
sum = innerTask.Result;
}
}
tcs.SetResult(sum);
callback(tcs.Task);
});
}
public int EndDoWork(IAsyncResult result)
{
try
{
return ((Task<int>)result).Result;
}
catch (AggregateException ex)
{
throw ex.InnerException;
}
}
}
My questions here are:
This code is using three threads: one that is instanced in the
BeginDoWork, another one that is instanced when the code enter
inside the anonymous method ContinueWhenAll, and the last one when
the callback is executed, in this case EndDoWork. Is that correct or
I’m doing something wrong on the calls? Should I use any
synchronization context? Note: The synchronization context is null
on the main thread.
What happen if I “share” information between
threads, for instance, the callback function? Will that cause a
performance issue or the anonymous method is like a closure where I
can share data?
With Framework 4.5 and Async and Await
Now with Framework 4.5, the code seems too much simple than before:
public async Task<int> DoWorkAsync(int count)
{
var proxyOne = new Backend.ServiceOne.ServiceOneClient();
var proxyTwo = new Backend.ServiceTwo.ServiceTwoClient();
var doWorkOne = proxyOne.DoWorkAsync(count);
var doWorkTwo = proxyTwo.DoWorkAsync(count);
var result = await Task.WhenAll(doWorkOne, doWorkTwo);
return doWorkOne.Result + doWorkTwo.Result;
}
But in this case when I debug the application, I always see that the code is executed on the same thread. So my questions here are:
3.. When I’m waiting for the “awaitable” code, is that thread released and goes back to the thread pool to execute more requests?
3.1. If So, I suppose that when I get a result from the await Task, the execution completes on the same thread that the call before. Is that possible? What happen if that thread is processing another request?
3.2 If Not, how can I release the thread to send it back to the thread pool with Asycn and Await pattern?
Thank you!
1. This code is using three threads: one that is instanced in the BeginDoWork, another one that is instanced when the code enter inside the anonymous method ContinueWhenAll, and the last one when the callback is executed, in this case EndDoWork. Is that correct or I’m doing something wrong on the calls? Should I use any synchronization context?
It's better to think in terms of "tasks" rather than "threads". You do have three tasks here, each of which will run on the thread pool, one at a time.
2. What happen if I “share” information between threads, for instance, the callback function? Will that cause a performance issue or the anonymous method is like a closure where I can share data?
You don't have to worry about synchronization because each of these tasks can't run concurrently. BeginDoWork registers the continuation just before returning, so it's already practically done when the continuation can run. EndDoWork will probably not be called until the continuation is complete; but even if it is, it will block until the continuation is complete.
(Technically, the continuation can start running before BeginDoWork completes, but BeginDoWork just returns at that point, so it doesn't matter).
3. When I’m waiting for the “awaitable” code, is that thread released and goes back to the thread pool to execute more requests?
Yes.
3.1. If So, I suppose that when I get a result from the await Task, the execution completes on the same thread that the call before. Is that possible? What happen if that thread is processing another request?
No. Your host (in this case, ASP.NET) may continue the async methods on any thread it happens to have available.
This is perfectly safe because only one thread is executing at a time.
P.S. I recommend
var result = await Task.WhenAll(doWorkOne, doWorkTwo);
return result[0] + result[1];
instead of
var result = await Task.WhenAll(doWorkOne, doWorkTwo);
return doWorkOne.Result + doWorkTwo.Result;
because Task.Result should be avoided in async programming.