Add grails-transactional-events v8 guide#509
Open
jamesfredley wants to merge 2 commits into
Open
Conversation
Cross-domain business logic in Grails using Spring application events with @TransactionalEventListener(AFTER_COMMIT). The pattern works out-of-the-box with GORM because GORM rides on Spring's PlatformTransactionManager: AFTER_COMMIT listeners fire when (and only when) the publisher's transaction commits, and are silently skipped on rollback. Sample-app-flavour Grails 8 guide that walks through: - An OrderService that publishes an OrderPlacedEvent POGO from a @transactional method via ApplicationEventPublisher. - Three independent listeners (CustomerLifetimeValueListener, AuditListener, NotificationListener) wired purely by Spring @TransactionalEventListener annotations on grails-app/services/ beans. - An @async + @TransactionalEventListener composition for off-thread dispatch, with @EnableAsync wiring on the Application class. - A reference table of all four TransactionPhase values (BEFORE_COMMIT, AFTER_COMMIT, AFTER_ROLLBACK, AFTER_COMPLETION). - A side-by-side contrast with GORM domain-class lifecycle callbacks and Grails' @subscriber / @Listener annotations. - A Spock @Integration spec that opens its own committed and rolled-back transactions to prove the AFTER_COMMIT contract. Registry entry added to conf/guides.yml with the standard v8 sample-app shape (sourcePath, tags, sampleRef pointing at grails-guides/grails-transactional-events grails8 branch, full toc). ./gradlew validateGuides -PvalidationMode=both passes (94 guides, 0 errors). ./gradlew renderGuide_grails_transactional_events_8 renders all 17 chapters with every include:: directive resolved. Assisted-by: claude-code:claude-opus-4-7
There was a problem hiding this comment.
Pull request overview
Adds a new sample-app-style Grails 8 guide covering Spring transactional application events for after-commit cross-domain side effects in GORM-backed applications.
Changes:
- Registers
grails-transactional-eventsv8 inconf/guides.yml. - Adds guide chapters explaining the transactional event pattern, listener phases, async dispatch, and integration testing.
- Adds sample snippets for domains, services/listeners, bootstrap data, event POGO, and integration spec.
Reviewed changes
Copilot reviewed 28 out of 28 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
conf/guides.yml |
Registers the new guide, metadata, tags, sample repo, and TOC. |
guides/grails-transactional-events/v8/guide/gettingStarted.adoc |
Introduces the guide’s transactional events pattern. |
guides/grails-transactional-events/v8/guide/whatYouWillBuild.adoc |
Summarizes the sample application artifacts. |
guides/grails-transactional-events/v8/guide/requirements.adoc |
Lists guide prerequisites. |
guides/grails-transactional-events/v8/guide/howto.adoc |
Provides clone-and-run instructions. |
guides/grails-transactional-events/v8/guide/createApp.adoc |
Describes starter app creation and dependencies. |
guides/grails-transactional-events/v8/guide/download.adoc |
Shows start.grails.org download commands. |
guides/grails-transactional-events/v8/guide/domainModel.adoc |
Documents the sample domain model. |
guides/grails-transactional-events/v8/guide/eventClass.adoc |
Explains the POGO event class. |
guides/grails-transactional-events/v8/guide/publishingEvents.adoc |
Covers publishing events from OrderService. |
guides/grails-transactional-events/v8/guide/transactionalListener.adoc |
Explains the first after-commit listener. |
guides/grails-transactional-events/v8/guide/transactionPhases.adoc |
Documents TransactionPhase options. |
guides/grails-transactional-events/v8/guide/multipleListeners.adoc |
Adds the audit listener fan-out example. |
guides/grails-transactional-events/v8/guide/asyncDispatch.adoc |
Explains @Async listener dispatch. |
guides/grails-transactional-events/v8/guide/vsGormEvents.adoc |
Compares Spring transactional events with GORM/Grails events. |
guides/grails-transactional-events/v8/guide/integrationTest.adoc |
Documents the integration test strategy. |
guides/grails-transactional-events/v8/guide/helpWithGrails.adoc |
Includes the shared help chapter. |
guides/grails-transactional-events/v8/snippets/grails-app/domain/example/Customer.groovy |
Adds the customer domain snippet. |
guides/grails-transactional-events/v8/snippets/grails-app/domain/example/Order.groovy |
Adds the order domain snippet. |
guides/grails-transactional-events/v8/snippets/grails-app/domain/example/AuditLog.groovy |
Adds the audit log domain snippet. |
guides/grails-transactional-events/v8/snippets/src/main/groovy/example/events/OrderPlacedEvent.groovy |
Adds the immutable event payload snippet. |
guides/grails-transactional-events/v8/snippets/grails-app/services/example/OrderService.groovy |
Adds the transactional publisher service snippet. |
guides/grails-transactional-events/v8/snippets/grails-app/services/example/CustomerLifetimeValueListener.groovy |
Adds the customer lifetime value listener snippet. |
guides/grails-transactional-events/v8/snippets/grails-app/services/example/AuditListener.groovy |
Adds the audit listener snippet. |
guides/grails-transactional-events/v8/snippets/grails-app/services/example/NotificationListener.groovy |
Adds the async notification listener snippet. |
guides/grails-transactional-events/v8/snippets/grails-app/init/example/BootStrap.groovy |
Adds sample bootstrap data. |
guides/grails-transactional-events/v8/snippets/src/integration-test/groovy/example/OrderServiceIntegrationSpec.groovy |
Adds integration coverage for commit and rollback behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Four factual corrections to the guide narrative. No code-snippet changes; the sample app at grails-guides/grails-transactional-events is unaffected. 1. transactionPhases.adoc / transactionalListener.adoc: "publisher's GORM session is closed" overstates the Spring lifecycle. After-commit synchronizations run after commit but BEFORE cleanupAfterCompletion(), so resources may still be bound to the thread. Rephrased to: the original transaction has already concluded, and the listener body cannot piggy-back on a transaction that has finished - hence REQUIRES_NEW. Same fix applied to both chapters. 2. whatYouWillBuild.adoc: "Two Spock integration specs" mismatched the actual snippet, which is one @Integration spec (OrderServiceIntegrationSpec) with two test methods. Bullet rewritten to match. 3. asyncDispatch.adoc: SimpleAsyncUncaughtExceptionHandler logs at ERROR (verified from Spring source: logger.error(...)), not WARN. Replaced the inaccurate log-level reference and expanded the operational advice about installing an explicit handler. ./gradlew validateGuides -PvalidationMode=both still passes (94 guides, 0 errors). renderGuide_grails_transactional_events_8 re-renders all 17 chapters with zero warnings; the four corrected paragraphs appear in the per-chapter and single-page HTML. Assisted-by: claude-code:claude-opus-4-7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a new Grails 8 guide:
Cross-Domain Logic in Grails with Transactional Spring Events
The pattern - publish a POGO from a
@Transactionalservice viaApplicationEventPublisher, consume it from any number of@TransactionalEventListener(phase = AFTER_COMMIT)beans - is the cleanest answer to "trigger business logic across several unrelated domains after a domain object changes state, but only if the change actually commits". It works out-of-the-box with GORM because GORM rides on Spring'sPlatformTransactionManager: the AFTER_COMMIT synchronisation callback fires exactly when the GORM transaction commits to the database, and is silently skipped on rollback. There is no Grails-specific bridge.This gap is not covered by any current Grails 8 guide. The existing
grails-eventsguide (v3 / v4) walks through the Grails-native EventBus /@Subscribermodel, which fires at the Hibernate-event level rather than the Spring-transaction level - the wrong tool for cross-domain "only on durable commit" side-effects.Sample-app flavour
The guide is sample-app flavour. The matching upstream repo lives at
grails-guides/grails-transactional-eventson thegrails8branch (initialised separately).Chapter arc (17 chapters)
gettingStartedwhatYouWillBuildrequirementshowtotheProblemafterInsert, plainApplicationEvent) failcreateApp/downloaddomainModelCustomer,Order,AuditLogeventClassOrderPlacedEventPOGO undersrc/main/groovy/example/events/publishingEventsOrderService.placeOrder()with@Transactional+ApplicationEventPublishertransactionalListener@TransactionalEventListener(AFTER_COMMIT)transactionPhasesTransactionPhasevaluesmultipleListenersasyncDispatch@Async+@TransactionalEventListener+@EnableAsyncvsGormEvents@Subscriber/@ListenerintegrationTest@Integrationspec proving rollback semanticshelpWithGrailsLocal verification
All 17 chapters render with every
include::../snippets/...[]directive resolved (10 source files cited in the rendered HTML).Files
conf/guides.yml- new entry in alphabetical position (betweengrails-test-securityandgrails-tvmlapp), categoryGrails Async, full v8-style toc with sub-keys mirroring the recent v8 batch (grails-rest-library,grails-spock-test-tour,grails-vite-spa).guides/grails-transactional-events/v8/guide/*.adoc- 17 chapters.guides/grails-transactional-events/v8/snippets/- 10 source files (3 domains, 4 services, 1 BootStrap, 1 POGO event, 1 integration spec).Related
grails-guides/grails-transactional-eventsongrails8branch (initialised separately by the PMC).grails-rest-libraryv8 andgrails-spock-test-tourv8 (both recent sample-app-flavour Grails 8 guides).