Tenant-Aware Dead-Letter Queues
The dead-letter queue is tenant-aware when multi-tenancy is enabled. The framework provides one routing queue and registry; each operation resolves the tenant from its ProcessingContext and delegates to that tenant’s concrete queue.
Enable the dead-letter queue for the processor as described in Dead-Letter Queue. Then provide a TenantAwareSequencedDeadLetterQueueFactory that creates the concrete JPA, JDBC, or in-memory queue for a tenant. The factory should obtain tenant-specific persistence resources from your application’s tenant-scoped components.
The ordinary SequencedDeadLetterQueueFactory is not replaced by your application code. Multi-tenancy installs the routing adapter automatically via enhancer and uses the tenant-aware factory you configure.
In Spring Boot, register the TenantAwareSequencedDeadLetterQueueFactory as a bean and enable the processor’s DLQ property. The bean is the only additional multi-tenancy DLQ integration point; your factory implementation still needs access to the tenant-specific datasource or entity manager it uses.
The following examples configure a JDBC queue. They assume that the application already registers a tenant-scoped DataSource provider as described in Tenant-scoped components.
-
Declarative configuration
-
Spring Boot
public void configure(MessagingConfigurer configurer) {
configurer.componentRegistry(registry -> registry.registerComponent(
TenantAwareSequencedDeadLetterQueueFactory.class,
configuration -> (tenant, processorName, queueConfiguration) -> createQueue(
tenant, processorName, queueConfiguration
))
);
}
private JdbcSequencedDeadLetterQueue<EventMessage> createQueue(
TenantDescriptor tenant,
String processorName,
Configuration configuration
) {
TenantComponentProvider<DataSource> dataSourceProvider =
TenantComponentProviderUtil.find(configuration, DataSource.class)
.orElseThrow();
JdbcTransactionalExecutorProvider executor =
new JdbcTransactionalExecutorProvider(dataSourceProvider.componentFor(tenant));
return JdbcSequencedDeadLetterQueue.<EventMessage>builder()
.processingGroup(processorName)
.transactionalExecutorProvider(ignored -> executor.getTransactionalExecutor(
null
))
.eventConverter(configuration.getComponent(EventConverter.class))
.genericConverter(configuration.getComponent(GeneralConverter.class))
.build();
}
@Bean
public TenantAwareSequencedDeadLetterQueueFactory tenantAwareDeadLetterQueueFactory() {
return (tenant, processorName, queueConfiguration) -> createQueue(tenant, processorName, queueConfiguration);
}
private JdbcSequencedDeadLetterQueue<EventMessage> createQueue(
TenantDescriptor tenant,
String processorName,
Configuration configuration
) {
TenantComponentProvider<DataSource> dataSourceProvider =
TenantComponentProviderUtil.find(configuration, DataSource.class)
.orElseThrow();
JdbcTransactionalExecutorProvider executor =
new JdbcTransactionalExecutorProvider(dataSourceProvider.componentFor(tenant));
return JdbcSequencedDeadLetterQueue.<EventMessage>builder()
.processingGroup(processorName)
.transactionalExecutorProvider(ignored -> executor.getTransactionalExecutor(
null
))
.eventConverter(configuration.getComponent(EventConverter.class))
.genericConverter(configuration.getComponent(GeneralConverter.class))
.build();
}