Skip to content

@TransactionalStep#400

Merged
devhawk merged 24 commits into
mainfrom
devhawk/tx-step-sb
May 27, 2026
Merged

@TransactionalStep#400
devhawk merged 24 commits into
mainfrom
devhawk/tx-step-sb

Conversation

@devhawk
Copy link
Copy Markdown
Collaborator

@devhawk devhawk commented May 26, 2026

Adds transact-spring-txstep-starter, a new Spring Boot auto-configuration module that brings @TransactionalStep to Spring applications.

What it does:

  • Introduces @TransactionalStep, a method annotation that marks a Spring-managed method as an idempotent DBOS step. The method body runs inside a REQUIRES_NEW Spring transaction; the return value is written to tx_step_outputs atomically with the user's database work. On workflow retry, the recorded output is replayed without re-executing the method body.
  • TransactionalStepAspect intercepts annotated methods and delegates to TransactionalStepFactory, which calls DBOS.runStep() and uses DataSourceUtils.getConnection() to write step output on the same transaction-bound connection.
  • TransactionalStepAutoConfiguration wires up the factory and aspect as Spring beans, auto-configured via AutoConfiguration.imports.
  • TransactionalStepRegistrar scans the Spring context post-startup and calls factory.initialize() (creates tx_step_outputs) only when annotated methods are found — no DB contact for apps that don't use the annotation.
  • JPA support: TransactionalStepFactory auto-detects JpaTransactionManager and sets its dataSource property to bridge JPA transactions to DataSourceUtils.

Supported stacks (all covered by integration tests):

  • Spring JDBC / JdbcTemplate
  • JDBI (jdbi3-spring transaction binding)
  • jOOQ (spring-boot-starter-jooq)
  • JPA / Hibernate (spring-boot-starter-data-jpa)

This PR also fixes previously implemented step factory's handling of concurrent updates. If two executors race to run the same step, both may pass the initial checkExecution read before either has committed. Previously, both executors transactions would commit, with the 2nd recordOutput INSERT being ignored. This has been fixed so the race loser's recordOutput INSERT into tx_step_outputs hits the (workflow_id, step_id) unique constraint. The factory catches the resulting 23505 violation and converts it to a StepConflictException. The calling code catches StepConflictException, rolls back the REQUIRES_NEW transaction (discarding the loser's database work), then re-reads tx_step_outputs to return the winner's committed result:
The outcome is idempotent from the caller's perspective: both executors return the same winner result, and only the winner's database write is committed.

Also includes minor refactors to JdbcStepFactory, JdbiStepFactory, and JooqStepFactory to extract shared SQL into TxStepSchema helpers, and expands their test suites.

fixes #385

Copy link
Copy Markdown
Member

@kraftp kraftp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall, the new interface is great for Spring! I did an AI review and it flagged some idiomatic Java things, probably worth checking them but they could be nothing.

Comment thread transact-spring-txstep-starter/README.md
@devhawk devhawk requested a review from kraftp May 27, 2026 17:10
Comment thread transact-spring-txstep-starter/README.md Outdated
Copy link
Copy Markdown
Member

@kraftp kraftp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@devhawk devhawk merged commit 3a23ab8 into main May 27, 2026
17 checks passed
@devhawk devhawk deleted the devhawk/tx-step-sb branch May 27, 2026 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@TransactionalStep for SpringBoot

2 participants