Difference between FireAndForget and Async behavior for publishing - redis

Currently, we are using StackExchange.Redis and, as it does not provides "blocking pops", we are doing as suggested on the documentation:
db.ListLeftPush(key, newWork, flags: CommandFlags.FireAndForget);
sub.Publish(channel, "");
What is the difference from this to the following?
db.ListLeftPushAsync(key, newWork);
sub.Publish(channel, "");
We know the purpose of the commands, what we would like to know is if it has any difference internally or any risk of behaving differently? (Execution order etc.)

There's a main difference comparing fire and forget vs calling an async operation and not awaiting it.
Fire and forget means that not only you're not waiting for the result but you don't care if it works or not, while an async operation may throw an exception once it has ended if something goes wrong.
In the other hand, when you issue a fire and forget command, StackExchange.Redis doesn't try to retrieve the command result internally, which is better if you just want the so-called fire and forget behavior when issuing commands.
You may check this difference if you open ConnectionMultiplexer source code and you see how ExecuteAsyncImpl / ExecuteSyncImpl methods are implemented:
// For example, ExecuteAsyncImpl...
if (message.IsFireAndForget)
{
TryPushMessageToBridge(message, processor, null, ref server);
return CompletedTask<T>.Default(null); // F+F explicitly does not get async-state
}
else
{
var tcs = TaskSource.CreateDenyExecSync<T>(state);
var source = ResultBox<T>.Get(tcs);
if (!TryPushMessageToBridge(message, processor, source, ref server))
{
ThrowFailed(tcs, ExceptionFactory.NoConnectionAvailable(IncludeDetailInExceptions, message.Command, message, server));
}
return tcs.Task;
}
Answer to some OP comment
Hi. Thanks for your answer. We know the purpose of the commands, what
we would like to know is if it has any differrence internally or any
risk of behaving differently (execution order etc.)
Since the async operation won't be finished when you publish the message on the Redis channel, it can happen that you publish the message and the operation gets executed never. You lose a lot of control.
When you send a fire and forget command, it mightn't be executed too, but you know that the try was done before you publish the channel's message. Therefore, you shouldn't use async operations to implement fire and forget pattern when using StackExchange.Redis.
You may check this other related Q&A: Stackexchange.redis does fire and forget guarantees delivery?

Related

ReactiveRedisOperations not saving object in Redis

I am using ReactiveRedisOperations to save data objects in Redis and this call returns a Mono as per the api.
I notice that if I don't do anything with this Mono return than this code does not do anything.
Just trying to understand how this works.
I would like below code to save every Object to Redis in this loop, however it does not do so, please share what is missing here.
for (SomeObject obj : list) {
reactiveRedisOperations.opsForHash().put(key, hashKey, obj).map(b -> obj); }
On the other side if i return the Mono result from similar code via a rest service response than it seems to save in Redis correctly, not sure why this is this way. Thanks
This is a quirk of reactive streams, not Lettuce.
Unlike a completable future which begins execution when it's created, a stream won't begin executing (the command isn't sent) until a consumer has subscribed to it.
I believe this is to facilitate backpressure, so a slow consumer isn't flooded with data by the producer.
Some nice reading -> https://blog.knoldus.com/working-with-project-reactor-reactive-streams/
If you return a Mono, to the underlying web framework, which generally will handle subscribe(ing) to this Mono, the respective operation will trigger resulting in whatever side-effects such as data being created in your Redis datastore.
Shall you wish to have your operations executed, you should do the same, i.e. subscribe to the publisher (Mono, or Flux) or return these data wrappers to whatever calling function you would know will handle this for you as in the aforementioned example:
Flux.fromIterable(list)
.flatMap(obj -> reactiveRedisOperations.opsForHash().put(key, hashKey, obj))
.subscribe();

ASP.NET Core Endpoint of type Task<T> returns fine without any await...how?

Updated below...
So this is a random question that came about from a discussion over what I consider the over usage of await in projects at work...
Not sure why I never tried it until now, other than the fact that it's weird and random, but the fact it does work just makes me wonder...how?
The .Result usage was only used to get the responseMessage. I know that is blocking and no bueno and it is for demo purposes only...
So this endpoint works fine...nothing is awaited
[HttpGet("kitteh")]
public Task<string> GetCatFact()
{
var client = new HttpClient();
var res = client.GetAsync("https://catfact.ninja/fact").Result;
return res.Content.ReadAsStringAsync();
}
There's obviously something in the default ASP.NET pipleline that ultimately unwraps the task in order to return the result...but where...or how?
Is this "less efficient" than awaiting in the endpoint itself as the magic taking place behind the scenes is ultimately just blocking to get the result of the returned task?
Updated
So, I am still skeptical and don't think the answer is as easy as "yes it is blocking" or "not it is not blocking" unless there's some legit proof or something to indicate one way or the other. I tried digging through the code myself, and I still don't have a solid answer but...I do know more than I did before...
I simplified the endpoints I have been testing this with...
[HttpGet("taskstring")]
public Task<string> TaskString()
{
return Task.FromResult("Where does this block?");
}
[HttpGet("asyncstring")]
public async Task<string> AsyncString()
{
return await Task.FromResult("This definitely doesn't block");
}
I stepped through a bunch of code and ultimately landed on ObjectMethodExecutor and AwaitableObjectResultExecutor which sparked some interest.
What appears to happen for both the endpoint versions above is the same or nearly the same, at least the execution of these two endpoints and the code covered below. There's a boatload that goes on during this and even though the rider debugger is great, it's not possible to see a lot of the values while debugging due to "Evaluation is not allowed: The thread is not at a GC-safe point".
When the endpoint is called but prior to the endpoint beginning execution...
ObjectMethodExecutor.ctor is called
This does a lot of inspection of the endpoint to determine a bunch of things
One of the checks is to is determine if the method is "async" and it ultimately calls AwaitableInfo.IsTypeAwaitable to check for the required methods/properties and interfaces to ensure it is
If it is, which in the case of returning Task of string it is, makes sense given the above info
ObjectMethodExecutor.GetExecutorAsync() is called
AwaitableObjectResultExecutor.Execute is then called
this type inherits ActionMethodExecutor which overrides the Execute method
executor.ExecuteAsync(executor type of ObjectMethodExecutorAwaitable) is then called, and awaited
this returns a result of type object, boxing yeah I know
The endpoint then actually executes and returns to AwaitableObjectResultExecutor.Execute
the result is then passed to ConvertToActionResult along with the return type, the T of Task of T and the mapper implementation
the mapped ActionResult is then returned
So...I'm still not certain 100% either way but there is a lot of effort put into inspecting the endpoint that is being called and determining if it's async or not, which would make it seem logical to think this is an attempt to avoid something...maybe blocking?
So...does it block...maybe? Seeing that there is an await from the indirect caller of the endpoint, I'd lean towards, no...but it seems really difficult to say still.
What I do now know is...
It definitely does await the endpoint call, albeit indirectly
It converts the Task of string return type to an IActionResult
An async and task only version seem to follow the exact some flow shown above
A non async version does not
So, based on all of that...#Phil's answer seems to be pretty spot on with what I found...
"The framework supports asynchronous controller actions. In order to do so, it would need to inspect the return value of your methods. If the method returns a Task, it will ultimately await on the result before responding.
Even if your action itself does all the awaiting, it still has to return a Task so the caller will still wait (the alternative being some ugly blocking code)."
Thanks to all for participating in an extremely random question that doesn't hold much value to truly understand
Your assumption here is basically correct...
There's obviously something in the default ASP.NET pipleline that ultimately unwraps the task in order to return the result
The framework supports asynchronous controller actions. In order to do so, it would need to inspect the return value of your methods. If the method returns a Task, it will ultimately await on the result before responding.
Even if your action itself does all the awaiting, it still has to return a Task so the caller will still wait (the alternative being some ugly blocking code).
As has been pointed out in some other posts, there are some performance improvements to be had by not awaiting a returned Task so I would write your action as
public async Task<string> GetCatFact()
{
var client = new HttpClient();
var res = await client.GetAsync("https://catfact.ninja/fact");
return res.Content.ReadAsStringAsync(); // no await
}
Your controller handles waiting for the remote response but delegates waiting for the content stream to the caller.
There's obviously something in the default ASP.NET pipleline that ultimately unwraps the task in order to return the result...but where...or how?
ASP.NET asynchronously waits for your task to complete, and then it sends the HTTP response based on the result of the task. It's logically similar to await: an asynchronous wait.
Is this "less efficient" than awaiting in the endpoint itself as the magic taking place behind the scenes is ultimately just blocking to get the result of the returned task?
Yes. It is less efficient to block.
ASP.NET doesn't block; it asynchronously waits. Blocking ties up a thread. So when the code calls .Result, it will be using a thread just to wait for that HttpClient call to complete.
The proper solution is to keep async and await:
[HttpGet("kitteh")]
public async Task<string> GetCatFact()
{
var client = new HttpClient();
var res = await client.GetAsync("https://catfact.ninja/fact");
return await res.Content.ReadAsStringAsync();
}
This way, while the GetAsync is in progress, the thread is yielded back to the ASP.NET runtime and is available for handling other requests, instead of being blocked waiting for the GetAsync to complete.
More information: Task<string> is part of the method signature. ASP.NET has special understanding of the Task<T> type and knows to asynchronously wait for it. async is not part of the method signature. ASP.NET knows whether your method returns Task, but it has no idea whether it's async (and doesn't care). So, in some situations, it's OK to elide the keywords (as described on my blog, but only when the method implementation is trivial. If there's any logic in the method, keep the async and await.

Proper logging in reactive application - WebFlux

last time I am thinking about proper using logger in our applications.
For example, I have a controller which returns a stream of users but in the log, I see the "Fetch Users" log is being logged by another thread than the thread on the processing pipeline but is it a good approach?
#Slf4j
class AwesomeController {
#GetMapping(path = "/users")
public Flux<User> getUsers() {
log.info("Fetch users..");
return Flux.just(...)..subscribeOn(Schedulers.newParallel("my-custom"));
}
}
In this case, two threads are used and from my perspective, not a good option, but I can't find good practices with loggers in reactive applications. I think below approach is better because allocation memory is from processing thread but not from spring webflux thread which potential can be blocking but logger.
#GetMapping(path = "/users")
public Flux<User> getUsers() {
return Flux.defer(() -> {
return Mono.fromCallable(() -> {
log.info("Fetch users..");
.....
})
}).subscribeOn(Schedulers.newParallel("my-custom"))
}
The normal thing to do would be to configure the logger as asynchronous (this usually has to be explicit as per the comments, but all modern logging frameworks support it) and then just include it "normally" (either as a separate line as you have there, or in a side-effect method such as doOnNext() if you want it half way through the reactive chain.)
If you want to be sure that the logger's call isn't blocking, then use BlockHound to make sure (this is never a bad idea anyway.) But in any case, I can't see a use case for your second example there - that makes the code rather difficult to follow with no real advantage.
One final thing to watch out for - remember that if you include the logging statement separately as you have above, rather than as part of the reactive chain, then it'll execute when the method at calltime rather than subscription time. That may not matter in scenarios like this where the two happen near simultaneously, but would be rather confusing if (for example) you're returning a publisher which may be subscribed to multiple times - in that case, you'd only ever see the "Fetch users..." statement once, which isn't obvious when glancing through the code.

Service Fabric self-deleting service

I'd like to add a service that executes some initialization operations for the system when it's first created.
I'd imagine it would be a stateless service (with cluster admin rights) that should self-destruct when it's done it's thing. I am under the impression that exiting the RunAsync function allows me to indicate that I'm finished (or in an error state). However, then it still hangs around on the application's context and annoyingly looking like it's "active" when it's not really doing anything at all.
Is it possible for a service to remove itself?
I think maybe we could try using the FabricClient.ServiceManager's DeleteServiceAsync (using parameters based on the service context) inside an OnCloseAsync override but I've not been able to prove that might work and it feels a little funky:
var client = new FabricClient();
await client.ServiceManager.DeleteServiceAsync(new DeleteServiceDescription(Context.ServiceName));
Is there a better way?
Returning from RunAsync will end the code in RunAsync (indicate completion), so SF won't start RunAsync again (It would if it returned an exception, for example). RunAsync completion doesn't cause the service to be deleted. As mentioned, for example, the service might be done with background work but still listening for incoming messages.
The best way to shut down a service is to call DeleteServiceAsync. This can be done by the service itself or another service, or from outside the cluster. Services can self-delete, so for services whose work is done we typically see await DeleteServiceAsync as the last line of RunAsync, after which the method just exits. Something like:
RunAsync(CancellationToken ct)
{
while(!workCompleted && !ct.IsCancellationRequested)
{
if(!DoneWithWork())
{
DoWork()
}
if(DoneWithWork())
{
workCompleted == true;
await DeleteServiceAsync(...)
}
}
}
The goal is to ensure that if your service is actually done doing the work it cleans itself up, but doesn't trigger its own deletion for the other reasons that a CancellationToken can get signaled, such as shutting down due to some upgrade or cluster resource balancing.
As mentioned already, returning from RunAsync will end this method only, but the service will continue to run and hence not be deleted.
DeleteServiceAsync certainly is the way to go - however it's not quite as simple as just calling it because if you're not careful it will deadlock on the current thread (especially in local developer cluster). You would also likely get a few short-lived health warnings about RunAsync taking a long time to terminate and/or target replica size not being met.
In any case - solution is quite simple - just do this:
private async Task DeleteSelf(CancellationToken cancellationToken)
{
using (var client = new FabricClient())
{
await client.ServiceManager.DeleteServiceAsync(new DeleteServiceDescription(this.Context.ServiceName), TimeSpan.FromMinutes(1), cancellationToken);
}
}
Then, in last line of my RunAsync method I call:
await DeleteSelf(cancellationToken).ConfigureAwait(false);
The ConfigureAwait(false) will help with deadlock issue as it will essentially return to a new thread synchronization context - i.e. not try to return to "caller context".

how to cancel WCF service call?

I have a WCF function that is executing long time, so I call the function in UI with backgraundworker... I want to give a feature to cancel the execution, so I abort IComunicationObject, the problem is that Service execution is not stoping, Is there any way to stop Service execution in this case?
You may not need a BackgroundWorker. You can either make the operation IsOneWay, or implement the asynchronous pattern. To prevent threading issues, consider using the SynchronizationContext. Programming WCF Services does a great job at explaining these.
Make a CancelOperation() method which sets some static ManualResetEvent in your service. Check this event in your Operation method frequently. Or it can be CancelOperation(Guid operationId) if your service can process multiple operation calls concurrently.
One important thing to understand if you're using the Async calls is that there's still no way to cancel a request and prevent a response coming back from the service once it's started. It's up to your UI to be intelligent in handling responses to avoid race conditions. Fortunately there's a simple way of doing this.
This example is for searching orders - driven by a UI. Lets assume it may take a few seconds to return results and the user is running two searches back to back.
Therefore if your user runs two searches and the first search returns after the second - you need to make sure you don't display the results of the first search.
private int _searchRequestID = 0; // need one for each WCF method you call
// Call our service...
// The call is made using the overload to the Async method with 'UserToken'.
// When the call completes we check the ID matches to avoid a nasty
// race condition
_searchRequestID = _searchRequestID++;
client.SearchOrdersCompleted += (s, e) =>
{
if (_searchRequestID != (int)e.UserState))
{
return; // avoid nasty race condition
}
// ok to handle response ...
}
client.SearchOrdersAsync(searchMessage, _searchRequestID);