-1

I'm using knex transaction with async/await syntax as suggested in this question: Get Knex.js transactions working with ES7 async/await

My problem is, that when transaction fails and trx callback is invoked, knex logs

Unhandled rejection error: relation "some_table" doesn't exist // Example error which I used for testing

just under the same error logged by logger, so logs looks like that:

// Removed error stacks...

// Error logged by logger
2019-07-14T23:12:29.606Z [error]: error: insert into "tab1" ("col1", "col2", "col3") values ($1, $2, $3) returning "col3" - relation "tab1" does not exist

// Koa.js error from ctx.throw()
InternalServerError: Internal Server Error

// Error when invoking await trx.rollback(e)
Unhandled rejection error: relation "tab1" does not exist

What I want to achive is to call trx.rollback(e) without throwing unhandled rejection error.

And the code causing this problem:

async function create (ctx) {
  const trx = await tools.promisify(knex.transaction.bind(knex))
  try {
    let [var1] = await trx('tab1').insert({...}).returning(['x', 'y'])

    // tab2 doesn't exist to trigger an error
    const [var2] = await trx('tab2').insert({...}).returning('z')

    await trx.commit()
  } catch (e) {
    await trx.rollback(e)
    logger.error(e)
    ctx.throw()
  }
}
Maksymilian Tomczyk
  • 1,100
  • 8
  • 16
  • Literally remove the line `ctx.throw()` – James Jul 15 '19 at 00:26
  • @James, thanks for your reply. Unfortunately, removing `ctx.throw()` doesn't resolve issue. – Maksymilian Tomczyk Jul 15 '19 at 01:43
  • Are you sure that there's a rollback to be done? I'm thinking that the transaction never committed b/c it threw an error before trx.commit(). – Dov Rine Jul 15 '19 at 06:42
  • @DovRine Yes, an error occurs before `trx.commit()`, but if I just skip `trx.rollback()` idle connections remains in PostgreSQL server. – Maksymilian Tomczyk Jul 15 '19 at 06:46
  • @MaksymilianTomczyk: Connections, but not a transaction waiting to commit. Did the inserts happen? It doesn't seem like it. Maybe you need to get handles to the db connections and close them manually in the error-handler. Isn't there a trx.abort() or something? (Sorry, I haven't used knex in about 5 years.) – Dov Rine Jul 15 '19 at 07:03
  • @DovRine No, inserts doesn't happen when error is throwed before `trx.commit()`. I also tried to remove `trx.rollback()` and `trx.commit()`, but then inserts are not performed. Maybe it's knex problem... – Maksymilian Tomczyk Jul 15 '19 at 18:33
  • You don't need to rollback if the commits never happen. The issue now is releasing the resources that trx is using bc it will never complete. – Dov Rine Jul 15 '19 at 19:45
  • Looking at the docs, it seems like they are recommending async transactions. This would eliminate your respurce errors bc knex manages them automatically. https://knexjs.org/#Transactions – Dov Rine Jul 15 '19 at 19:51
  • I can't find an oppsite method to trx.start(),so I assume that it's supposed to bbe garbage collected normally. Maybe you can reassign trx to null or something to force gc. – Dov Rine Jul 15 '19 at 19:53

1 Answers1

1

You are using transactions wrong... try this:

async function create (ctx) {
  try {
    const res = await knex.transaction(async trx => {
      let [var1] = await trx('tab1').insert({...}).returning(['x', 'y'])
      // tab2 doesn't exist to trigger an error
      const [var2] = await trx('tab2').insert({...}).returning('z')

      return [var1, var2];
    });
  } catch (e) {
    logger.error(e)
    ctx.throw()
  }
}

Also if you really want you can use latest knex 0.18 and transactionProvider()... it is found from knex docuementation... but in your case 1st way works even better and will be more robust that explicit commit.

Real answer to your question is that the line:

trx = await tools.promisify(knex.transaction.bind(knex))

doesn't bind any handlers to promise chain returned by knex.transaction(trx => {...}) call and then when you call .rollback(e) that chain rejects and leaks that exception.

Mikael Lepistö
  • 18,909
  • 3
  • 68
  • 70