Tenant-Aware Command Processing

Tenant-aware command handling covers how commands can be dispatched and handled in a tenant aware Axon application.

Command dispatching

With multi-tenancy enabled, command dispatching is automatically tenant-aware. No changes to how you use the CommandGateway or CommandBus are required.

Each known tenant has its own Axon Server connection. When a command handler is subscribed, that subscription is applied across every known tenant, so a single subscription serves commands for all tenants. A tenant that becomes known after a handler was subscribed, automatically receives that same subscription, so newly added tenants are served without any extra configuration.

When a command is dispatched, the tenant is resolved as described in the tenant resolution section, and the command is routed to the Axon Server context of that tenant.

The tenant resolved for a command must be one of the currently known tenants. If the resolved tenant is not currently known, for example because its context was removed after the tenant was resolved, dispatch fails with a TenantNotResolvedException.

Command handling

Command handling methods are registered the same way as in a single-tenant application. No change to how you declare or register a command handler is required.

During handling, the tenant of the command is resolved again on the handling side and made available for the rest of that message’s processing. This is what allows a tenant-scoped component, such as a per-tenant external service, to be injected into a handler’s parameters: the framework knows which tenant’s instance to provide because the tenant has already been established for that message.

@CommandHandler
public void on(NotifyCourseSubscription command, @TenantScoped NotificationService notificationService, EventAppender appender) { (1)
    notificationService.notifyStudentCourseCreation(command.studentId(), command.courseId());
    appender.append(new CourseSubscriptionNotified(command.courseId(),
                command.studentId()));
}
1 notificationService is the NotificationService instance specific for the current tenant. The @TenantScoped annotation marks it as tenant scoped, transparently resolved by a tenant aware parameter resolver.

See Tenant-scoped components for more details on how to register such components and inject them into a handler.

If the tenant cannot be resolved on the handling side, handling proceeds without a tenant available for that message. Injecting a tenant-scoped component parameter then fails with a TenantNotResolvedException, as described in Tenant-scoped components.