Asynchronous Processing
Overview
The StarterKit supports both synchronous and asynchronous events. Synchronous events are built on MediatR INotification and are executed directly before the UnitOfWork.Commit completes, whereas asynchronous events are queued and executed outside of the request.
Send
Asynchronous events are built on MassTransit (with ServiceBus transport). There are two ways to send an asynchronous event:
- Using the
IEntity.EventsandIAggregatedRoot.Eventscollections, where the event must be marked with theIAsyncNotificationinterface (IAsyncNotificationis a child interface ofINotification, thus it can be listened to in both synchronous and asynchronous contexts). - Directly through the
IEventPublisherPort.
Note that events will only be sent to the queue after calling IUnitOfWork.CommitAsync().
Inbox/Outbox
Interacting with 3rd-party services can sometimes introduce unexpected and inconsistent failures into programs, such as:
- When called before commit, the message was sent but the database transaction failed.
- When called before commit, the message was sent and processed before the database transaction completed.
- When called after commit, the transaction was completed but message sending failed.
By utilizing the Inbox/Outbox pattern provided by MassTransit, we can ensure the transactionality of message sending. Database transaction and message sending occur as a single unit. If the database transaction fails, the message will not be sent to the queue and vice versa. More information on this can be found in the MassTransit documentation Transactional Outbox.
Consume
To add a new consumer event, simply create a new class inheriting from IConsumer<YourEvent> in StarterKit.App.Infrastructure/Events/Consumers. Its addition will automatically create an Azure Service Bus Topic (if not already created) as well as a Subscription.
In the base version of StarterKit, to avoid complicating deployment, background consumers start in the same process as the web application. This may lead to issues, as some cloud providers may stop processes if the web application is not in use (for example, Azure App Services). Therefore, StarterKit BICEP scripts are configured for an Always On configuration, but sometimes it may be necessary to separate Consumers from the main process.