c# – Using Commands and Service Bus

Question:

Let's say you have a web service that accepts a POST request to register a user. Initial implementation (intentionally very simplistic):

[HttpPost]
public ActionResult Post([FromBody]CustomerDTO value)
{
    try
    {
        _customerRepository.Create(value);
        return Ok();
    }
    catch (Exception ex)
    {
        return BadRequest(ex.Message);
    }
}

I wanted to distribute the load among several servers, and instead of waiting for a save in the repository, I want to send a "Register user" command to the bus. It will end up in a queue, for example, RabbitMQ. Further, this command will be processed by one of the servers that is subscribed to the execution of this command. Something like that:

[HttpPost]
public ActionResult Post([FromBody]CustomerDTO value)
{
    try
    {
        RegisterCustomerCommand command = MapFromDto<RegisterCustomerCommand>(value);
        _bus.Send(command)
        return Ok();
    }
    catch (Exception ex)
    {
        return BadRequest(ex.Message);
    }
}

...

public class RegisterCustomerCommandHandler: ICommandHandler<RegisterCustomerCommand>
{
    private ICustomerRepository _customerRepository;
    public RegisterCustomerCommandHandler(ICustomerRepository customerRepository)
    {
        _customerRepository = customerRepository;
    }
    public void Handle(RegisterCustomerCommand command)
    {
        _customerRepository.Create(GetDTOFromCommand(command));
    }
}

However, let's say, according to the logic of the application, we cannot register two users with the same E-mail. In the case of the implementation of the service bus, we have the danger of receiving requests for user registration with the same E-mail at the same time. The WebApi client will return a code 200, which means that the registration was successful. However, one of the teams will inevitably fall (since it will try to register a user with E-mail, which was already registered a couple of moments ago), but the client will not know about it.

Preliminary validation (is a user already registered with this Email?) Will not help here either – at the time of validation, he may not be registered, but at the time of command execution, he is already registered.

What do you think about this situation? What do you do in this case?

My thoughts on this: this implementation is perfect, for example, in the case when you need to send an email to the user with an Email confirmation link. We registered the user -> created the " CustomerRegistredEvent " event, sent it to the queue -> this event from the queue in n seconds will be picked up by the handler and sent a letter to the user. However, in "sensitive" cases, such as the one described above (user registration), you must wait for the entire command to complete. Perhaps, there is no need to use Command and Shin.

Answer:

Perhaps in the world of distributed systems, this task is solved differently, but if we ignore the specifics of a specific implementation, it looks like the most ordinary asynchronous task.

You register a command in the queue and give the user its identifier and the approximate time for which it will be executed. After this time, the user asks about the current state of the task. Receives either the result of the execution, or a new estimate in time. And so until the server tells the client that the task is completed with a certain result, or until the client gets tired of waiting (in which case it is worth at least trying to send a cancellation request), or until the task in some bad way disappears from history (n .p. if the server was rebooted). The client handles these situations on its own and either re-tries to complete the task, or informs the user that something went wrong.

Scroll to Top
AllEscort