Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will MediatR run the commands sequentially or in parallel?

I use MediatR and CQRS in an application. The following two statements exist in many modules and may be called concurrently in the application (It's a blazor application).

await Mediator.Send(new AddIdCommand { Id = id });

and

await Mediator.Send(new DeleteIdCommand { Id = id });

The following are the commands, which update the same text file.

public class AddIdCommand : IRequest
{
    public int Id { get; set; }

    public class AddIdCommandHandler : IRequestHandler<DeleteIdCommand>
    {
        public async Task<Unit> Handle(AddIdCommand request, CancellationToken cancellationToken)
        {
            // .... update the text file with the Id deleted
        }
    }
}

public class DeleteIdCommand : IRequest
{
    public int Id { get; set; }

    public class DeleteIdCommandHandler : IRequestHandler<DeleteIdCommand>
    {
        public async Task<Unit> Handle(DeleteIdCommand request, CancellationToken cancellationToken)
        {
            // .... update the text file with the Id added
        }
    }
}

 ....
    protected IMediator Mediator => _mediator ??= HttpContext.RequestServices.GetService<IMediator>();

Will the Handle(...) in the two commands be called sequentially always? (So no need to worry about multiple processes updating the same file issue.)

like image 601
ca9163d9 Avatar asked Oct 18 '25 01:10

ca9163d9


1 Answers

Well, only from the context of these two lines:

await Mediator.Send(new AddIdCommand { Id = id });
await Mediator.Send(new DeleteIdCommand { Id = id });

It will run sequentially.

You can see the code here:

https://github.com/jbogard/MediatR/blob/master/src/MediatR/Mediator.cs

var requestType = request.GetType();

var handler = (RequestHandlerWrapper<TResponse>)_requestHandlers.GetOrAdd(requestType,
    t => Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<,>).MakeGenericType(requestType, typeof(TResponse))));

return handler.Handle(request, cancellationToken, _serviceFactory);

It simply returns the task of your async Handle method. So if you await the subsequent handle methods, it's running synchronously(relatively to each other).

But you end your question with

So no need to worry about multiple processes updating the same file issue.

And I'm not sure about that. Even if you are awaiting both send methods, if there's two independent proceses calling these two methods, and all of them target same file, the order between them won't be guaranteed. The only synchronization Mediator.cs is doing for a multi-threaded application is that _requestHandlers is a ConcurrentDictionary.

So it guarantees that this line will never initialize multiple handlers for the same type, even when called in parallel:

var handler = (RequestHandlerWrapper<TResponse>)_requestHandlers.GetOrAdd(requestType,
        t => Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<,>).MakeGenericType(requestType, typeof(TResponse))));

The Handle calls are not synchronized.

like image 82
Erndob Avatar answered Oct 20 '25 14:10

Erndob