Skip to content

Commit 3e62d5f

Browse files
authored
Merge pull request #18 from imqueue/fix-pgiplock-init
fix: different schemas for different types of lock & check if schema …
2 parents c79000b + 1d44f22 commit 3e62d5f

File tree

1 file changed

+47
-31
lines changed

1 file changed

+47
-31
lines changed

src/PgIpLock.ts

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ export class PgIpLock implements AnyLock {
5656
*
5757
* @return {string}
5858
*/
59-
public static get schemaName(): string {
60-
return ident(SCHEMA_NAME);
59+
public get schemaName(): string {
60+
const suffix = this.uniqueKey ? '_unique' : '';
61+
62+
return ident(SCHEMA_NAME + suffix);
6163
}
6264

6365
/**
@@ -110,8 +112,10 @@ export class PgIpLock implements AnyLock {
110112
* @return {Promise<void>}
111113
*/
112114
public async init(): Promise<void> {
113-
await this.createSchema();
114-
await Promise.all([this.createLock(), this.createDeadlockCheck()]);
115+
if (!await this.schemaExists()) {
116+
await this.createSchema();
117+
await Promise.all([this.createLock(), this.createDeadlockCheck()]);
118+
}
115119

116120
if (this.notifyHandler && !this.uniqueKey) {
117121
this.options.pgClient.on('notification', this.notifyHandler);
@@ -184,6 +188,21 @@ export class PgIpLock implements AnyLock {
184188
return this.acquired;
185189
}
186190

191+
/**
192+
* Returns true if lock schema exists, false - otherwise
193+
*
194+
* @return {Promise<boolean>}
195+
*/
196+
private async schemaExists(): Promise<boolean> {
197+
const { rows } = await this.options.pgClient.query(`
198+
SELECT schema_name
199+
FROM information_schema.schemata
200+
WHERE schema_name = '${this.schemaName}'
201+
`);
202+
203+
return (rows.length > 0);
204+
}
205+
187206
/**
188207
* Acquires a lock with ID
189208
*
@@ -192,16 +211,15 @@ export class PgIpLock implements AnyLock {
192211
private async acquireUniqueLock(): Promise<void> {
193212
// noinspection SqlResolve
194213
await this.options.pgClient.query(`
195-
INSERT INTO ${PgIpLock.schemaName}.lock (id, channel, app)
214+
INSERT INTO ${this.schemaName}.lock (id, channel, app)
196215
VALUES (
197216
${literal(this.uniqueKey)},
198217
${literal(this.channel)},
199218
${literal(this.options.pgClient.appName)}
200219
) ON CONFLICT (id) DO
201-
UPDATE SET app = ${PgIpLock.schemaName}.deadlock_check(
202-
${PgIpLock.schemaName}.lock.app,
203-
${literal(this.options.pgClient.appName)},
204-
NOW()
220+
UPDATE SET app = ${this.schemaName}.deadlock_check(
221+
${this.schemaName}.lock.app,
222+
${literal(this.options.pgClient.appName)}
205223
)
206224
`);
207225
}
@@ -214,15 +232,14 @@ export class PgIpLock implements AnyLock {
214232
private async acquireChannelLock(): Promise<void> {
215233
// noinspection SqlResolve
216234
await this.options.pgClient.query(`
217-
INSERT INTO ${PgIpLock.schemaName}.lock (channel, app)
235+
INSERT INTO ${this.schemaName}.lock (channel, app)
218236
VALUES (
219237
${literal(this.channel)},
220238
${literal(this.options.pgClient.appName)}
221239
) ON CONFLICT (channel) DO
222-
UPDATE SET app = ${PgIpLock.schemaName}.deadlock_check(
223-
${PgIpLock.schemaName}.lock.app,
224-
${literal(this.options.pgClient.appName)},
225-
NOW()
240+
UPDATE SET app = ${this.schemaName}.deadlock_check(
241+
${this.schemaName}.lock.app,
242+
${literal(this.options.pgClient.appName)}
226243
)
227244
`);
228245
}
@@ -237,7 +254,7 @@ export class PgIpLock implements AnyLock {
237254
if (this.uniqueKey) {
238255
// noinspection SqlResolve
239256
await this.options.pgClient.query(`
240-
DELETE FROM ${PgIpLock.schemaName}.lock
257+
DELETE FROM ${this.schemaName}.lock
241258
WHERE id=${literal(this.uniqueKey)}
242259
`);
243260
} else {
@@ -247,7 +264,7 @@ export class PgIpLock implements AnyLock {
247264

248265
// noinspection SqlResolve
249266
await this.options.pgClient.query(`
250-
DELETE FROM ${PgIpLock.schemaName}.lock
267+
DELETE FROM ${this.schemaName}.lock
251268
WHERE channel=${literal(this.channel)}
252269
`);
253270
}
@@ -319,7 +336,7 @@ export class PgIpLock implements AnyLock {
319336
*/
320337
private async createSchema(): Promise<void> {
321338
await this.options.pgClient.query(`
322-
CREATE SCHEMA IF NOT EXISTS ${PgIpLock.schemaName}
339+
CREATE SCHEMA IF NOT EXISTS ${this.schemaName}
323340
`);
324341
}
325342

@@ -351,25 +368,25 @@ export class PgIpLock implements AnyLock {
351368
IF NOT EXISTS (
352369
SELECT *
353370
FROM information_schema.columns
354-
WHERE table_schema = '${ PgIpLock.schemaName }'
371+
WHERE table_schema = '${ this.schemaName }'
355372
AND table_name = 'lock'
356373
AND column_name = 'id'
357374
) THEN
358-
DROP TABLE IF EXISTS ${ PgIpLock.schemaName }.lock;
375+
DROP TABLE IF EXISTS ${ this.schemaName }.lock;
359376
END IF;
360377
END
361378
$$
362379
`);
363380
await this.options.pgClient.query(`
364-
CREATE TABLE IF NOT EXISTS ${ PgIpLock.schemaName }."lock" (
381+
CREATE TABLE IF NOT EXISTS ${ this.schemaName }."lock" (
365382
"id" CHARACTER VARYING NOT NULL PRIMARY KEY,
366383
"channel" CHARACTER VARYING NOT NULL,
367384
"app" CHARACTER VARYING NOT NULL
368385
)
369386
`);
370387
await this.options.pgClient.query(`
371388
DROP TRIGGER IF EXISTS notify_release_lock_trigger
372-
ON ${PgIpLock.schemaName}.lock
389+
ON ${this.schemaName}.lock
373390
`);
374391
}
375392

@@ -385,40 +402,40 @@ export class PgIpLock implements AnyLock {
385402
IF EXISTS (
386403
SELECT *
387404
FROM information_schema.columns
388-
WHERE table_schema = '${ PgIpLock.schemaName }'
405+
WHERE table_schema = '${ this.schemaName }'
389406
AND table_name = 'lock'
390407
AND column_name = 'id'
391408
) THEN
392-
DROP TABLE IF EXISTS ${ PgIpLock.schemaName }.lock;
409+
DROP TABLE IF EXISTS ${ this.schemaName }.lock;
393410
END IF;
394411
END
395412
$$
396413
`);
397414
await this.options.pgClient.query(`
398-
CREATE TABLE IF NOT EXISTS ${ PgIpLock.schemaName }."lock" (
415+
CREATE TABLE IF NOT EXISTS ${ this.schemaName }."lock" (
399416
"channel" CHARACTER VARYING NOT NULL PRIMARY KEY,
400417
"app" CHARACTER VARYING NOT NULL
401418
)
402419
`);
403420
// noinspection SqlResolve
404421
await this.options.pgClient.query(`
405-
CREATE OR REPLACE FUNCTION ${PgIpLock.schemaName}.notify_lock()
422+
CREATE OR REPLACE FUNCTION ${this.schemaName}.notify_lock()
406423
RETURNS TRIGGER LANGUAGE PLPGSQL AS $$
407424
BEGIN PERFORM PG_NOTIFY(OLD.channel, '1'); RETURN OLD; END; $$
408425
`);
409426

410427
await this.options.pgClient.query(`
411428
DROP TRIGGER IF EXISTS notify_release_lock_trigger
412-
ON ${PgIpLock.schemaName}.lock
429+
ON ${this.schemaName}.lock
413430
`);
414431

415432
try {
416433
await this.options.pgClient.query(`
417434
CREATE CONSTRAINT TRIGGER notify_release_lock_trigger
418-
AFTER DELETE ON ${PgIpLock.schemaName}.lock
435+
AFTER DELETE ON ${this.schemaName}.lock
419436
DEFERRABLE INITIALLY DEFERRED
420437
FOR EACH ROW EXECUTE PROCEDURE ${
421-
PgIpLock.schemaName}.notify_lock()
438+
this.schemaName}.notify_lock()
422439
`);
423440
} catch (e) {
424441
/*ignore*/
@@ -432,10 +449,9 @@ export class PgIpLock implements AnyLock {
432449
*/
433450
private async createDeadlockCheck(): Promise<void> {
434451
await this.options.pgClient.query(`
435-
CREATE OR REPLACE FUNCTION ${PgIpLock.schemaName}.deadlock_check(
452+
CREATE OR REPLACE FUNCTION ${this.schemaName}.deadlock_check(
436453
old_app TEXT,
437-
new_app TEXT,
438-
call_time TIMESTAMP WITH TIME ZONE
454+
new_app TEXT
439455
)
440456
RETURNS TEXT LANGUAGE PLPGSQL AS $$
441457
DECLARE num_apps INTEGER;

0 commit comments

Comments
 (0)