Skip to content

Use AsyncLocalStorage for transaction context support #13889

@ajwootto

Description

@ajwootto

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the feature has not already been requested

🚀 Feature Proposal

A few other ORMs use the NodeJS AsyncLocalStorage API to provide a more ergonomic way of using transactions. One example is Sequelize: https://sequelize.org/docs/v7/querying/transactions/#disabling-cls

Basically this allows someone to write a bunch of business logic that might span several different function calls etc. while having all the ORM database calls automatically use a transaction that was started earlier in the callstack, without having to pass an object like session around and manually provide it to each ORM call.

I think this would be a pretty powerful alternative interface for transactions

Motivation

We are writing an API where we have a use-case that requires us to start a transaction at the beginning of every request and then use it for each DB operation that occurs within that request's business logic, before committing the transaction at the end.

Currently that requires us to find our own way to pass the session object around, eg:

async function requestHandler() {
  await connection.withTransaction(async (session) => {
     await someBusinessLogic(session)
 
  }
}

async function someBusinessLogic(session) {
 // need to explicitly provide session
  MyModel.findOneAndUpdate({}, {}, {session})
}

but with this proposal you wouldn't need to provide the session:

async function requestHandler() {
  await connection.withTransactionContext(async (session) => {
     await someBusinessLogic()
 
  }
}

async function someBusinessLogic() {
 // automatically uses transaction by finding it via AsyncLocalStorage context provided by `withTransactionContext` wrapper
   MyModel.findOneAndUpdate({}, {})
}

Example

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementThis issue is a user-facing general improvement that doesn't fix a bug or add a new featurenew featureThis change adds new functionality, like a new method or class

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions