numtel / pg-live-select

Live Updating PostgreSQL SELECT statements
https://www.npmjs.com/package/pg-live-select
Other
55 stars 9 forks source link

Concurrency error #12

Closed JaredBoone closed 6 years ago

JaredBoone commented 6 years ago

If you run pg-live-select in multiple processes concurrently, postgres throws "ERROR: tuple concurrently updated". This happens because CREATE FUNCTION (from triggers.sql.tpl) can't be used concurrently.

JaredBoone commented 6 years ago

I have worked around this by wrapping the SQL in trigger.sql.tpl in a transaction that includes a transaction-level advisory lock as follows:

BEGIN;
SELECT pg_advisory_xact_lock(510127006994284723); --64 bit unsigned int
CREATE OR REPLACE FUNCTION ... 
$$ LANGUAGE plpgsql;
COMMIT;

See https://stackoverflow.com/questions/40525684/tuple-concurrently-updated-when-creating-functions-in-postgresql-pl-pgsql for more details.

JaredBoone commented 6 years ago

In case anyone else runs into this, the package owner informed me that the channel string must be unique for each child process. Here's an example of how to do this:

parent.js:

const { fork } = require('child_process');
const numForks = 2;
for (var i = 0; i < numForks; i++) {
    var child = fork(require.resolve('./child.js'), [], { env: {
      CONN: 'postgres://meteor:meteor@127.0.0.1/meteor',
      CHANNEL: 'chan_'+i } });
}

child.js:

const LivePG = require('pg-live-select');
var liveDb;
process.on('exit', () => {
   if (liveDb) {
        liveDb.cleanup(() => console.log('cleaned up'));
    }
});
liveDb = new LivePG(process.env.CONN, process.env.CHANNEL)
liveDb.select('SELECT * FROM assignments')
    .on('update', function (diff, data) {
        console.log(process.env.CHANNEL + ': ', data);
    });