Class RedisOutboxAutoConfiguration
redis-outbox-backend module
(Wave A.2 Phase 0b).
EXPLICIT backend selection (refinement #11). Activated ONLY when
im2be.outbox.enabled=true AND im2be.outbox.backend=REDIS.
Redis being on the classpath must NOT auto-select Redis — PG stays the
default. The im2be.outbox.backend property is owned by the
outbox-publisher's OutboxProperties (the OutboxProperties.Backend
enum already declares PG + REDIS); this autoconfig keys off the
REDIS value via @ConditionalOnProperty.
When this autoconfig is active it supplies the OutboxBackend bean
(RedisOutboxBackend). The outbox-publisher's PG
@ConditionalOnMissingBean OutboxBackend therefore backs off — but note
that the PG OutboxAutoConfiguration ALSO eagerly wires JPA beans
(repository, completion helper) that a Redis-only consumer (identity-service)
must not trigger. That JPA-conditional wiring is tracked as a Phase-0b/Phase-1
follow-up in the PG OutboxAutoConfiguration Javadoc (it is a
cross-module change to a FROZEN Phase 0a file, out of scope here); a Redis-only
service simply does NOT put spring-data-jpa on its classpath, so the PG
autoconfig's @AutoConfigureAfter(DataSourceAutoConfiguration…) +
JPA-dependent bean methods never resolve. This module deliberately does not
depend on spring-data-jpa for exactly that reason.
Wires:
StringRedisTemplate(@ConditionalOnMissingBean) — string keys/JSON values; sorted-set scores numeric.RedisOutboxScripts— the loaded Lua singletons.RedisOutboxKeys— the hash-tagged key set.RedisOutboxMetrics— no-op when noMeterRegistry.RedisOutboxBackend— theOutboxBackendimpl.RedisOutboxRelay— inline hot relay (own Resilience4j breaker).RedisOutboxPollerWorker— cold sweep (conditional onim2be.outbox.redis.poller.enabled, default true).RedisDurabilityValidator— startup + periodic AOF/fsync/noeviction guard.RedisOutboxRetentionWorker/RedisOutboxRepairWorker— scheduled SENT-retention + zset/hash repair (each conditional on its.enabledflag, default true).
@EnableScheduling activates the @Scheduled poller +
durability + retention + repair ticks. Side effect (be aware): because
@EnableScheduling registers ScheduledAnnotationBeanPostProcessor
for the WHOLE application context, enabling im2be.outbox.backend=REDIS
also activates Spring's task scheduler for the consumer — any consumer
@Scheduled beans that were dormant (because the consumer had not itself
opted into scheduling) start running. The blast is scoped to consumers that
explicitly opt into the Redis backend, but consumer teams should know that
selecting this backend turns the scheduler on context-wide. This side effect
is INTRINSIC, not narrowable by moving @EnableScheduling to a nested
@Configuration gated on poller.enabled: the durability
validator, retention worker, and repair worker are ALSO @Scheduled
(durability is even unconditional), so scheduling is required whenever the
backend is REDIS, not merely when the poller is on — a poller-only
gate would silently stop those workers. And Spring's @EnableScheduling
registers ScheduledAnnotationBeanPostProcessor for the whole context
wherever it is declared, so a nested activator would not actually scope the
leak. True per-module isolation would mean dropping @Scheduled for a
module-private programmatic TaskScheduler — a deliberate non-goal for
this module; the documented context-wide opt-in is the accepted trade-off
(reviewer R1 INFO / R2 MINOR — kept as documented). Registered via
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports.
-
Constructor Summary
ConstructorsConstructorDescriptionRedisOutboxAutoConfiguration(RedisOutboxProperties properties) Validates cross-field properties that JSR-303 field annotations cannot express, then logs the active backend. -
Method Summary
Modifier and TypeMethodDescriptionredisDurabilityValidator(org.springframework.data.redis.core.StringRedisTemplate redis, RedisOutboxProperties properties, RedisOutboxMetrics metrics) The durability validator (startup + periodic AOF/fsync/noeviction guard, refinement #7).redisOutboxBackend(org.springframework.data.redis.core.StringRedisTemplate redis, RedisOutboxScripts scripts, RedisOutboxKeys keys, RedisOutboxBackoff backoff, RedisOutboxMetrics metrics, org.springframework.beans.factory.ObjectProvider<com.fasterxml.jackson.databind.ObjectMapper> objectMapper) TheOutboxBackendbean — satisfies the outbox-publisher's@ConditionalOnMissingBean OutboxBackendso the PG backend backs off (refinement #11).redisOutboxBackoff(RedisOutboxProperties properties) The exponential-backoff calculator for failure re-scoring (refinement #5).io.github.resilience4j.circuitbreaker.CircuitBreakerredisOutboxCircuitBreaker(RedisOutboxProperties properties, io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry registry) The Redis hot-relayCircuitBreaker, thresholds built explicitly fromim2be.outbox.redis.circuit-breaker.*so the config takes effect regardless of which registry the consumer wired.io.github.resilience4j.circuitbreaker.CircuitBreakerRegistryDefault Resilience4jCircuitBreakerRegistryfor consumers that have not declared one (vanilla defaults — outbox-specific thresholds live on the breaker created below, not the registry default, to avoid leaking into other breakers — parity with the PG autoconfig's R4 fix).redisOutboxKeys(RedisOutboxProperties properties) The hash-tagged key set derived fromim2be.outbox.redis.key-prefix(refinement #8).redisOutboxMetrics(org.springframework.beans.factory.ObjectProvider<io.micrometer.core.instrument.MeterRegistry> meterRegistry, org.springframework.data.redis.core.StringRedisTemplate redis, RedisOutboxKeys keys) The metrics binder.redisOutboxPollerWorker(OutboxBackend backend, org.springframework.kafka.core.KafkaTemplate<byte[], byte[]> kafkaTemplate, org.springframework.data.redis.core.StringRedisTemplate redis, RedisOutboxScripts scripts, RedisOutboxKeys keys, RedisOutboxProperties properties, RedisOutboxMetrics metrics) The cold poller.redisOutboxRelay(OutboxBackend backend, org.springframework.kafka.core.KafkaTemplate<byte[], byte[]> kafkaTemplate, io.github.resilience4j.circuitbreaker.CircuitBreaker redisOutboxCircuitBreaker, RedisOutboxMetrics metrics, RedisOutboxProperties properties) The inline hot relay (own breaker — the PG AFTER_COMMIT relay is unusable for a transaction-free backend; seeRedisOutboxRelay).redisOutboxRepairWorker(org.springframework.data.redis.core.StringRedisTemplate redis, RedisOutboxScripts scripts, RedisOutboxKeys keys, org.springframework.beans.factory.ObjectProvider<com.fasterxml.jackson.databind.ObjectMapper> objectMapper, RedisOutboxMetrics metrics) The zset/hash repair worker (refinement #10).redisOutboxRetentionWorker(org.springframework.data.redis.core.StringRedisTemplate redis, RedisOutboxScripts scripts, RedisOutboxKeys keys, org.springframework.beans.factory.ObjectProvider<com.fasterxml.jackson.databind.ObjectMapper> objectMapper, RedisOutboxProperties properties, RedisOutboxMetrics metrics) The SENT-retention worker (refinement #9).The Lua script singletons (SHA1 computed once — seeRedisOutboxScripts).org.springframework.data.redis.core.StringRedisTemplateredisOutboxStringRedisTemplate(org.springframework.data.redis.connection.RedisConnectionFactory connectionFactory) String-typed Redis template.
-
Constructor Details
-
RedisOutboxAutoConfiguration
Validates cross-field properties that JSR-303 field annotations cannot express, then logs the active backend.lockRenewMarginMsMUST be strictly less thanlockTtlMs(refinement #4 — the renew must fire before the lease ends), otherwise the poller could never renew in time.- Parameters:
properties- the bound Redis-outbox properties
-
-
Method Details
-
redisOutboxStringRedisTemplate
@Bean @ConditionalOnMissingBean public org.springframework.data.redis.core.StringRedisTemplate redisOutboxStringRedisTemplate(org.springframework.data.redis.connection.RedisConnectionFactory connectionFactory) String-typed Redis template.@ConditionalOnMissingBeanso a consumer with its own template (custom serializers, cluster client) wins.- Parameters:
connectionFactory- the application's Redis connection factory (provided byRedisAutoConfiguration)- Returns:
- a
StringRedisTemplate
-
redisOutboxScripts
The Lua script singletons (SHA1 computed once — seeRedisOutboxScripts).- Returns:
- the script holder
-
redisOutboxKeys
@Bean @ConditionalOnMissingBean public RedisOutboxKeys redisOutboxKeys(RedisOutboxProperties properties) The hash-tagged key set derived fromim2be.outbox.redis.key-prefix(refinement #8).- Parameters:
properties- the Redis-outbox properties- Returns:
- the key set
-
redisOutboxBackoff
@Bean @ConditionalOnMissingBean public RedisOutboxBackoff redisOutboxBackoff(RedisOutboxProperties properties) The exponential-backoff calculator for failure re-scoring (refinement #5).- Parameters:
properties- the Redis-outbox properties- Returns:
- the backoff
-
redisOutboxMetrics
@Bean @ConditionalOnMissingBean public RedisOutboxMetrics redisOutboxMetrics(org.springframework.beans.factory.ObjectProvider<io.micrometer.core.instrument.MeterRegistry> meterRegistry, org.springframework.data.redis.core.StringRedisTemplate redis, RedisOutboxKeys keys) The metrics binder. No-op when noMeterRegistryis present (parity with the PGOutboxMetricsBinder).- Parameters:
meterRegistry- optional Micrometer registryredis- the Redis template (for the pending-gauge poll)keys- the key set- Returns:
- the metrics binder
-
redisOutboxBackend
@Bean @ConditionalOnMissingBean(com.aim2be.platform.outbox.OutboxBackend.class) public RedisOutboxBackend redisOutboxBackend(org.springframework.data.redis.core.StringRedisTemplate redis, RedisOutboxScripts scripts, RedisOutboxKeys keys, RedisOutboxBackoff backoff, RedisOutboxMetrics metrics, org.springframework.beans.factory.ObjectProvider<com.fasterxml.jackson.databind.ObjectMapper> objectMapper) TheOutboxBackendbean — satisfies the outbox-publisher's@ConditionalOnMissingBean OutboxBackendso the PG backend backs off (refinement #11). Reuses the applicationObjectMapperwhen present, else a fresh one.- Parameters:
redis- the Redis templatescripts- the Lua scriptskeys- the key setbackoff- the failure-rescore backoffmetrics- the metrics binderobjectMapper- optional application Jackson mapper- Returns:
- the Redis outbox backend
-
redisOutboxCircuitBreakerRegistry
@Bean @ConditionalOnMissingBean public io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry redisOutboxCircuitBreakerRegistry()Default Resilience4jCircuitBreakerRegistryfor consumers that have not declared one (vanilla defaults — outbox-specific thresholds live on the breaker created below, not the registry default, to avoid leaking into other breakers — parity with the PG autoconfig's R4 fix).- Returns:
- a default breaker registry
-
redisOutboxCircuitBreaker
@Bean @ConditionalOnMissingBean(name="redisOutboxCircuitBreaker") public io.github.resilience4j.circuitbreaker.CircuitBreaker redisOutboxCircuitBreaker(RedisOutboxProperties properties, io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry registry) The Redis hot-relayCircuitBreaker, thresholds built explicitly fromim2be.outbox.redis.circuit-breaker.*so the config takes effect regardless of which registry the consumer wired.- Parameters:
properties- the Redis-outbox propertiesregistry- the breaker registry to register into- Returns:
- the relay breaker
-
redisOutboxRelay
@Bean @ConditionalOnMissingBean public RedisOutboxRelay redisOutboxRelay(OutboxBackend backend, org.springframework.kafka.core.KafkaTemplate<byte[], byte[]> kafkaTemplate, io.github.resilience4j.circuitbreaker.CircuitBreaker redisOutboxCircuitBreaker, RedisOutboxMetrics metrics, RedisOutboxProperties properties) The inline hot relay (own breaker — the PG AFTER_COMMIT relay is unusable for a transaction-free backend; seeRedisOutboxRelay).- Parameters:
backend- the Redis backend (transitions)kafkaTemplate- the Kafka templateredisOutboxCircuitBreaker- the relay breakermetrics- the metrics binderproperties- the Redis-outbox properties (max-retries)- Returns:
- the relay
-
redisOutboxPollerWorker
@Bean @ConditionalOnMissingBean @ConditionalOnProperty(prefix="im2be.outbox.redis.poller", name="enabled", havingValue="true", matchIfMissing=true) public RedisOutboxPollerWorker redisOutboxPollerWorker(OutboxBackend backend, org.springframework.kafka.core.KafkaTemplate<byte[], byte[]> kafkaTemplate, org.springframework.data.redis.core.StringRedisTemplate redis, RedisOutboxScripts scripts, RedisOutboxKeys keys, RedisOutboxProperties properties, RedisOutboxMetrics metrics) The cold poller. Conditional onim2be.outbox.redis.poller.enabled(default true).- Parameters:
backend- the Redis backendkafkaTemplate- the Kafka templateredis- the Redis template (lock acquire)scripts- the Lua scripts (lock renew/release)keys- the key setproperties- the Redis-outbox propertiesmetrics- the metrics binder- Returns:
- the poller worker
-
redisDurabilityValidator
@Bean @ConditionalOnMissingBean public RedisDurabilityValidator redisDurabilityValidator(org.springframework.data.redis.core.StringRedisTemplate redis, RedisOutboxProperties properties, RedisOutboxMetrics metrics) The durability validator (startup + periodic AOF/fsync/noeviction guard, refinement #7).- Parameters:
redis- the Redis template (CONFIG GET)properties- the Redis-outbox properties (durability config)metrics- the metrics binder- Returns:
- the validator
-
redisOutboxRetentionWorker
@Bean @ConditionalOnMissingBean @ConditionalOnProperty(prefix="im2be.outbox.redis.retention", name="enabled", havingValue="true", matchIfMissing=true) public RedisOutboxRetentionWorker redisOutboxRetentionWorker(org.springframework.data.redis.core.StringRedisTemplate redis, RedisOutboxScripts scripts, RedisOutboxKeys keys, org.springframework.beans.factory.ObjectProvider<com.fasterxml.jackson.databind.ObjectMapper> objectMapper, RedisOutboxProperties properties, RedisOutboxMetrics metrics) The SENT-retention worker (refinement #9). Conditional onim2be.outbox.redis.retention.enabled(default true).- Parameters:
redis- the Redis templatescripts- the Lua scriptskeys- the key setobjectMapper- the Jackson mapperproperties- the Redis-outbox properties (retention config)metrics- the metrics binder- Returns:
- the retention worker
-
redisOutboxRepairWorker
@Bean @ConditionalOnMissingBean @ConditionalOnProperty(prefix="im2be.outbox.redis.repair", name="enabled", havingValue="true", matchIfMissing=true) public RedisOutboxRepairWorker redisOutboxRepairWorker(org.springframework.data.redis.core.StringRedisTemplate redis, RedisOutboxScripts scripts, RedisOutboxKeys keys, org.springframework.beans.factory.ObjectProvider<com.fasterxml.jackson.databind.ObjectMapper> objectMapper, RedisOutboxMetrics metrics) The zset/hash repair worker (refinement #10). Conditional onim2be.outbox.redis.repair.enabled(default true).- Parameters:
redis- the Redis templatescripts- the Lua scriptskeys- the key setobjectMapper- the Jackson mappermetrics- the metrics binder- Returns:
- the repair worker
-