Skip to content

Documented "Postgres takes priority" is inverted: MysqlOutboxStore wins when both store modules are on the classpath #90

Description

@endrju19

The KDoc states twice that Postgres wins when both store modules are on the classpath:

  • OutboxAutoConfiguration.kt:54"If both are present, Postgres takes priority. Override by defining your own @Bean OutboxStore."
  • OutboxAutoConfiguration.kt:249"When both Postgres and MySQL modules are on the classpath, [PostgresStoreConfiguration] takes priority."

In practice MySQL wins.

Observed

A Spring Boot consumer with okapi-postgres and okapi-mysql on the classpath, running against a PostgreSQL database:

bean='outboxStore'  type=com.softwaremill.okapi.mysql.MysqlOutboxStore
SpringLiquibase : beans=1  names=[okapiMysqlLiquibase]

The context starts and the MySQL changelog is applied to the Postgres database (its DDL happens to be accepted), producing the MySQL table shape — id character(36), delivery_metadata json — instead of the Postgres one. Then every processor tick fails:

ERROR c.s.okapi.core.OutboxScheduler : Outbox processor tick failed, will retry at next scheduled interval
Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near "INDEX"
    at com.softwaremill.okapi.mysql.MysqlOutboxStore.claimPending(MysqlOutboxStore.kt:64)

FORCE INDEX (MysqlOutboxStore.kt:53) is MySQL-only syntax. publish() fails as well. The application looks healthy at startup and never delivers anything.

Why it is not caught

LiquibaseE2ETest asserts only that exactly one okapi*Liquibase bean activates, not which one:

val activeLiquibase = listOf("okapiPostgresLiquibase", "okapiMysqlLiquibase").filter { ctx.containsBean(it) }
activeLiquibase.size shouldBe 1

and its own comment already acknowledges the ambiguity: "Without this filter the OutboxStore precedence in the test JVM is non-deterministic between Postgres and MySQL". That test also sets okapi.processor.enabled=false, so claimPending is never exercised.

So the invariant the suite actually pins ("exactly one Liquibase activates") holds — it is the documented precedence that has no coverage.

Notes

This is not double instantiation: exactly one OutboxStore and one SpringLiquibase bean are created. The wrong one wins, decided by nested @Configuration processing order. Reproduced on v1.0.0 (e199775).

Having both modules on the classpath is a scenario the KDoc explicitly claims to handle, and it is reachable via a transitive dependency, a shared BOM, or an in-progress engine migration.

Possible directions

Either make the precedence deterministic and enforce it with a test that asserts which store wins, or — if it cannot be made deterministic — fail fast when both modules are present and no explicit @Bean OutboxStore disambiguates.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions