Search code examples
c#.net-coremasstransitsagarouting-slip

Is it possible to add dynamic data to an MassTransit courier/routing slip custom event?


I have a MassTransit routing slip configured and working. For reference, the routing slip takes in an ID of an item in a MongoDB database and then creates a "version" of that document in a SQL database using EF Core. The activities (as commands) are:

  1. Migrate document to SQL
  2. Update audit info in MongoDB document
  3. Update MongoDB document status (i.e. to published)

All of the above are write commands.

I have added a new 1st step which runs a query to make sure the MongoDB document is valid (e.g. name and description fields are completed) before running the migration. If this step fails it throws a custom exception, which in turns fires a failed event which is then picked up and managed by my saga. Below is a snippet of my activity code followed by the routing slip builder code:

Activity code

var result = await _queryDispatcher.ExecuteAsync<SelectModuleValidationResultById, ModuleValidationResult>(query).ConfigureAwait(false);

if (!result.ModuleValidationMessages.Any())
{
    return context.Completed();
}

return context.Faulted(new ModuleNotValidException
{
    ModuleId = messageCommand.ModuleId,
    ModuleValidationMessages = result.ModuleValidationMessages
});

Routing slip builder code

builder.AddActivity(
    nameof(Step1ValidateModule),
    context.GetDestinationAddress(ActivityHelper.BuildQueueName<Step1ValidateModule>(ActivityQueueType.Execute)),
    new SelectModuleValidationResultById(
        context.Message.ModuleId,
        context.Message.UserId,
        context.Message.LanguageId)
);

builder.AddSubscription(
    context.SourceAddress,
    RoutingSlipEvents.ActivityFaulted,
    RoutingSlipEventContents.All,
    nameof(Step1ValidateModule),
    x => x.Send<IModuleValidationFailed>(new
    {
        context.Message.ModuleId,
        context.Message.LanguageId,
        context.Message.UserId,
        context.Message.DeploymentId,
    }));

Whilst all of this works and the event gets picked up by my saga I would ideally like to add the ModuleValidationMessages (i.e. any failed validation messages) to the event being returned but I can't figure out how or even if that's possible (or more fundamentally if it's right thing to do).

It's worth noting that this is a last resort check and that the validation is checked by the client before even trying the migration so worse case scenario I can just leave it has "Has validation issues" but ideally I would like to include the derail in the failed response.


Solution

  • Good use case, and yes, it's possible to add the details you need to the built-in routing slip events. Instead of throwing an exception, you can Terminate the routing slip, and include variables - such as an array of messages, which are added to the RoutingSlipTerminated event that will be published.

    This way, it isn't a fault but more of a business decision to terminate the routing slip prematurely. It's a contextual difference, which is why it allows variables to be specified (versus Faulted, which is a full-tilt exception).

    You can then pull the array from the variables and use those in your saga or consumer.