Skip to content

transactionAsyncLocalStorage not honored in bulk operations like insertMany #14738

@mlh758

Description

@mlh758

Prerequisites

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

Mongoose version

8.4.0

Node.js version

20.15.0

MongoDB server version

6

Typescript version (if applicable)

No response

Description

The new transactionAsyncLocalStorage mechanism seems to work great for individual operations like save and create on models. It doesn't seem to be honored on bulk operations such as insertMany.

Steps to Reproduce

Forgive the slightly convoluted code here, we have a wrapper over mongoose models with some singleton logic for working in AWS Lambda.

This test passes as I'd expect:

it.only('supports transactions without explicitly passing the session object', async () => {
  mongoose.set('transactionAsyncLocalStorage', true);
  await ChildDao.instance.find({ filter: {}, context }); // just forcing a preflight to get a connection, ignore
  await ChildDao.instance.model.db
    .transaction(async () => {
      await ChildDao.instance.model.create({ name: 'test' });
      throw new Error('Rollback');
    })
    .catch(() => {});

  expect(await ChildDao.instance.model.findOne({ name: 'test' })).toBeNull();
});

This test fails:

it.only('supports transactions without explicitly passing the session object', async () => {
  mongoose.set('transactionAsyncLocalStorage', true);
  await ChildDao.instance.find({ filter: {}, context });
  await ChildDao.instance.model.db
    .transaction(async () => {
      await ChildDao.instance.model.insertMany([{ name: 'test' }]);
      throw new Error('Rollback');
    })
    .catch(() => {});

  expect(await ChildDao.instance.model.findOne({ name: 'test' })).toBeNull();
});

This test passes, explicitly passing the session:

it.only('supports transactions on bulk operations if explicitly passed a session', async () => {
  mongoose.set('transactionAsyncLocalStorage', true);
  await ChildDao.instance.find({ filter: {}, context });
  await ChildDao.instance.model.db
    .transaction(async (session) => {
      await ChildDao.instance.model.insertMany([{ name: 'test' }], { session });
      throw new Error('Rollback');
    })
    .catch(() => {});

  expect(await ChildDao.instance.model.findOne({ name: 'test' })).toBeNull();
});

Expected Behavior

The transactionAsyncLocalStorage should allow the more ergonomic flow for bulk operations as well. This might fall under a feature request, but without the caveats explained in the docs I'd be inclined to call it a bug.

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-bugWe've confirmed this is a bug in Mongoose and will fix it.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions