Using Transaction Events To Defer Actions

We can bind handlers to transaction events to easily defer specific actions until after the transaction has been committed and our changes have persisted to the database.

Transactions have two events we can bind handlers to.

  1. Commit - when the transaction persists its changes to the database

  2. Rollback - when the transaction reverts any changes applied to the database

Snippet Scenario

Let's say we have a Notification model. When new notification records are created we want to emit an event to send an email to the notification recipient.

However, our notification is created inside a transaction that's in charge of persisting other records besides our notification.

In case we run into any errors between our notification creation and our transaction commit, we'll only want to emit our event that sends the email when we know our transaction completes and our records are all persisted.

// inside a controller or service

const notification = new Notification()

if (trx) {

  initiatorUserId: user?.id,
  notificationTypeId: NotificationTypes.COMMENT,
  table: Comment.table,
  title: `${user.username} commented on your post`,
  body: UtilityService.truncate(comment.body),
  href: this.getGoPath(comment)

await notification.trySendEmail(, trx) // 👈 we'll dig into this

// ... other actions

await trx?.commit()

Here we're creating our notification record, which may or may not utilize a transaction.

// app/Models/Notification.ts

export default class Notification extends BaseModel {
  // ... other stuff

  public async trySendEmail(
    userId: number, 
    trx: TransactionClientContract | undefined | null = undefined
  ) {
    const user = await User.query()
      .where({ id: userId })
    // user doesn't want notified, skip send
    if (!this.isEmailEnabled(user.profile)) {

    // no transaction, go ahead and send then exit
    if (!trx) {
      return Event.emit('notification:send', { 
        notification: this, 

    // otherwise, wait for transaction to commit, then send
    trx.on('commit', () => {
      Event.emit('notification:send', { 
        notification: this, 

Join The Discussion! (0 Comments)

Please sign in or sign up for free to join in on the dicussion.