Tenant Sequencing
Tenant sequencing lets an application order message handling within one tenant without making every tenant wait for the same sequence.
The multi-tenancy module provides a TenantSequencingPolicy backed by the same tenant routing rules as the rest of the module.
It first uses the tenant carried by the processing context.
When the context carries no tenant, it falls back to the configured TenantResolver and checks the result against the known tenants.
Messages resolving to the same tenant use the same sequence identifier.
Messages resolving to different tenants can be handled independently.
When no known tenant can be resolved, the policy returns no sequence identifier.
That keeps unlabelled messages from accidentally sharing one global tenant sequence.
For a single sequence across every tenant, use the framework’s SequentialPolicy instead.
Configuration
Tenant command sequencing
Register TenantSequencingPolicy as the named command sequencing policy component:
public void configureCommandSequencing(MessagingConfigurer configurer) {
configurer.componentRegistry(registry -> registry.registerComponent(
SequencingPolicy.class,
MessagingConfigurationDefaults.COMMAND_SEQUENCING_POLICY,
configuration -> TenantSequencingPolicy.from(configuration.getComponent(TenantRouter.class))
));
}
For details on configuring a custom command sequencing policy see the Command sequencing chapter in the tuning section.
Tenant event sequencing
Create the event handling component with TenantSequencingPolicy:
public void configureEventSequencing(MessagingConfigurer configurer) {
configurer.eventProcessing(eventProcessing -> eventProcessing.pooledStreaming(
pooled -> pooled.processor(
EventProcessorModule.pooledStreaming("tenant-aware-projection")
.eventHandlingComponents(components -> components.declarative(
"tenant-aware-projection",
configuration -> {
var component = SimpleEventHandlingComponent.create(
"tenant-aware-projection",
TenantSequencingPolicy.from(
configuration.getComponent(TenantRouter.class)
)
);
component.subscribe(
new QualifiedName("example", "CourseUpdated"),
(event, context) -> MessageStream.empty()
);
return component;
}
))
.notCustomized()
)
));
}
For details on configuring a custom event sequencing policy see the sequential processing chapter in the streaming event processors section.