Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sequelize transactions as Express middleware

I'm trying to add Sequelize transactions to my Express app, but I'm unsuccessful. I'm using async/await across the app, and I've created the namespace using the 'cls-hooked' package as instructed on the docs for Sequelize transactions.

Sequelize.useCLS(require('cls-hooked').createNamespace('db'));

My middleware is pretty simple and looks something like this

module.exports = () => (req, res, next) => sequelize.transaction(async () => next());

and in app.js

app.use(sequelizeTransaction());
app.use('/api', apiRoutes);

I've also tried using the middleware directly on routes, but I get the same result as above

router.post('/', sequelizeTransaction(), async (req, res) => {
    await serviceThatDoesTwoDBOperations();
});

The result is that I get the transaction, but only around the first DB operation. Everything after that is ignored, and rollbacks aren't happening on errors. I'm probably doing something obviously wrong, but I can't put my finger on it.

like image 580
Migiyaka Avatar asked Oct 17 '22 23:10

Migiyaka


1 Answers

I was having the same issue as you. This is how I made it work. For some reason sequelize was clearing the transaction on the namespace before it was actually completed.

Also make sure that you are using node > 8.5 for the async_hooks.

export const transactionMiddleware = async (req, res, next) => {
  namespace.bindEmitter(req);
  namespace.bindEmitter(res);
  namespace.bind(next);
  namespace.run(async () => {
    const transaction = await sequelize.transaction();
    namespace.set('transaction', transaction);
    onFinished(res, (err) => {
      if (!err) {
        transaction.commit();
      } else {
        transaction.rollback();
      }
    });
    next();
  });
};

I hope that works for you :)

like image 174
Benjamim Avatar answered Oct 21 '22 05:10

Benjamim