question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Transactions with async/await?

See original GitHub issue

I’m running Node 7.5.0 with the --harmony flag, which enables support for async/await. I’m using the client pool with async/await, which works great and has a nice example here.

The example for transactions (here) uses callbacks instead of async/await, so I thought I’d try something like this as a quick test:

let client = null;

try {
    client = await this.pool.connect();
} catch (error) {
    console.log('A client pool error occurred:', error);
    return error;
}

try {
    await client.query('BEGIN');
    await client.query('UPDATE foo SET bar = 1');
    await client.query('UPDATE bar SET foo = 2');
    await client.query('COMMIT');
} catch (error) {
    try {
        await client.query('ROLLBACK');
    } catch (rollbackError) {
        console.log('A rollback error occurred:', rollbackError);
    }
    console.log('An error occurred:', error);
    return error;
} finally {
    client.release();
}

return 'Success!';

This seems to work just fine, but is this a bad idea? Is there some technical or other reason I should be using the callback approach with transactions?

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:9 (1 by maintainers)

github_iconTop GitHub Comments

47reactions
brianccommented, Apr 13, 2017

Because doing transactions are usually pretty application specific and node-postgres aims to be a low layer driver doing the nitty gritty communication between your app & postgres over the wire, I’ve intentionally left any higher-level transaction handling code out of the library. It’s 100% possible to do transactions with just node-postgres (this is what I do in my apps) but in my experience it always ends up looking custom to your application, particularly when inside the transaction the output of a query forms some of the input to a subsequent query.

That being said…your code looks similar to how I’ve done transactions within my own apps using async/await. You can even made a simple abstraction like this:

const tx = callback => {
  const client = await pool.connect()
  try {
  await client.query('BEGIN')
    try {
      await callback(client)
      client.query('COMMIT')
    } catch(e) {
      client.query('ROLLBACK')
    }
  } finally {
    client.release()
  }
}

This allows you, in your own app, to do things like:

const fromAccount = 100
const toAccount = 103
const transferAmount = 33
tx(async client => {
  const { rows } = await client.query('SELECT balance FROM account WHERE id = $1', [fromAccount])
  const balance = rows[0].balance
  if (balance > transferAmount) {
    await client.query('UPDATE account SET balance = $2 WHERE id = $1', [fromAccount, balance - transferAmount])
    await client.query('UPDATE account SET balance = $2 WHERE id = $1', [toAccount, balance + transferAmount])
  }
})

fwiw I avoid using callbacks directly in node whenever I can - I think async/await provides such a nicer abstraction it allows me to focus more on coding and less on juggling callback hell.

hope this helps 😄

4reactions
zerbfracommented, May 20, 2017

Here a different version, based on @brianc’s one! check it out 😃

https://gist.github.com/zerbfra/70b155fa00b4e0d6fd1d4e090a039ad4

Read more comments on GitHub >

github_iconTop Results From Across the Web

Node.js 7 how to use sequelize transaction with async / await?
Managed transaction in async/await style may look as follows: await sequelize.transaction( async t=>{ const user = User.create( { name: "Alex", pwd: "2dwe3dcd ...
Read more >
Transactions, callbacks, and async-await in the Realtime ...
Callbacks are running asynchronously and the async won't wait for them to finish. If you want to switch to async-await to leave callbacks...
Read more >
using await with transaction in sequelize ORM · GitHub
@legiahoang hello I am using same method inside to async.waterfall but is not working so please provide me any solution. router.post('/upload',async function( ...
Read more >
TransactionScope and Async/Await. Be one with the flow
An explicit transaction means we create a new instance of a CommittableTransaction in code and pass it from method to method as a...
Read more >
The Pitfalls of Async-Await - Shipbook
Let's say that to upload the average transaction, you need to calculate the average transaction value from the transaction history. Hence, you ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found