mythix-orm-postgresql 1.7.2 → 1.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/postgresql-connection.js +66 -13
- package/package.json +1 -1
|
@@ -7,10 +7,18 @@ const Nife = require('nife');
|
|
|
7
7
|
const { DateTime } = require('luxon');
|
|
8
8
|
const PG = require('pg');
|
|
9
9
|
const PGFormat = require('pg-format');
|
|
10
|
-
const { Literals }
|
|
10
|
+
const { Literals, Errors } = require('mythix-orm');
|
|
11
11
|
const { SQLConnectionBase } = require('mythix-orm-sql-base');
|
|
12
12
|
const PostgreSQLQueryGenerator = require('./postgresql-query-generator');
|
|
13
13
|
|
|
14
|
+
const DEFAULT_TIMEOUT_MS = 5000;
|
|
15
|
+
|
|
16
|
+
function sleep(ms) {
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
setTimeout(resolve, ms);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
14
22
|
class PostgreSQLConnection extends SQLConnectionBase {
|
|
15
23
|
static dialect = 'postgresql';
|
|
16
24
|
|
|
@@ -33,6 +41,27 @@ class PostgreSQLConnection extends SQLConnectionBase {
|
|
|
33
41
|
return !!this.pool;
|
|
34
42
|
}
|
|
35
43
|
|
|
44
|
+
async getPoolConnection(_retryCount) {
|
|
45
|
+
let retryCount = _retryCount || 0;
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
return await this.pool.connect();
|
|
49
|
+
} catch (error) {
|
|
50
|
+
let options = this.getOptions();
|
|
51
|
+
let connectMaxRetries = (options.connectMaxRetries == null) ? 5 : options.connectMaxRetries;
|
|
52
|
+
let connectRetryDelay = (options.connectRetryDelay == null) ? 5000 : options.connectRetryDelay;
|
|
53
|
+
|
|
54
|
+
if (error.code === 'ECONNREFUSED') {
|
|
55
|
+
if (retryCount < connectMaxRetries) {
|
|
56
|
+
await sleep(connectRetryDelay);
|
|
57
|
+
return this.getPoolConnection(retryCount + 1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
throw new Errors.MythixORMConnectionTimedOutError(error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
36
65
|
async start() {
|
|
37
66
|
let options = this.getOptions();
|
|
38
67
|
|
|
@@ -45,11 +74,10 @@ class PostgreSQLConnection extends SQLConnectionBase {
|
|
|
45
74
|
},
|
|
46
75
|
options,
|
|
47
76
|
{
|
|
48
|
-
statement_timeout: options.statementTimeout,
|
|
49
|
-
query_timeout: options.queryTimeout,
|
|
50
|
-
connectionTimeoutMillis: options.connectionTimeout,
|
|
77
|
+
statement_timeout: options.statementTimeout || DEFAULT_TIMEOUT_MS,
|
|
78
|
+
query_timeout: options.queryTimeout || DEFAULT_TIMEOUT_MS,
|
|
79
|
+
connectionTimeoutMillis: options.connectionTimeout || 60000,
|
|
51
80
|
idle_in_transaction_session_timeout: options.idleTransactionTimeout,
|
|
52
|
-
idleTimeoutMillis: options.idleConnectionTimeout,
|
|
53
81
|
max: options.maxPoolConnections,
|
|
54
82
|
},
|
|
55
83
|
);
|
|
@@ -73,6 +101,10 @@ class PostgreSQLConnection extends SQLConnectionBase {
|
|
|
73
101
|
pool.on('remove', (client) => {
|
|
74
102
|
this.emit('disconnect', client);
|
|
75
103
|
});
|
|
104
|
+
|
|
105
|
+
// Ensure that we can connect to the DB
|
|
106
|
+
let client = await this.getPoolConnection();
|
|
107
|
+
await client.release();
|
|
76
108
|
}
|
|
77
109
|
|
|
78
110
|
async stop() {
|
|
@@ -141,7 +173,7 @@ class PostgreSQLConnection extends SQLConnectionBase {
|
|
|
141
173
|
try {
|
|
142
174
|
client = _client || this.inTransaction;
|
|
143
175
|
if (!client) {
|
|
144
|
-
client = await this.
|
|
176
|
+
client = await this.getPoolConnection();
|
|
145
177
|
hasOwnClient = true;
|
|
146
178
|
}
|
|
147
179
|
|
|
@@ -155,8 +187,14 @@ class PostgreSQLConnection extends SQLConnectionBase {
|
|
|
155
187
|
else
|
|
156
188
|
result = await client.query(sql);
|
|
157
189
|
|
|
190
|
+
if (client && hasOwnClient)
|
|
191
|
+
await client.release();
|
|
192
|
+
|
|
158
193
|
return this.formatResultsResponse(sql, result);
|
|
159
194
|
} catch (error) {
|
|
195
|
+
if (client && hasOwnClient)
|
|
196
|
+
await client.release();
|
|
197
|
+
|
|
160
198
|
if (logger) {
|
|
161
199
|
logger.error(error);
|
|
162
200
|
logger.error('QUERY: ', sql);
|
|
@@ -165,13 +203,10 @@ class PostgreSQLConnection extends SQLConnectionBase {
|
|
|
165
203
|
error.query = sql;
|
|
166
204
|
|
|
167
205
|
throw error;
|
|
168
|
-
} finally {
|
|
169
|
-
if (client && hasOwnClient)
|
|
170
|
-
await client.release();
|
|
171
206
|
}
|
|
172
207
|
}
|
|
173
208
|
|
|
174
|
-
async transaction(callback, _options) {
|
|
209
|
+
async transaction(callback, _options, _retryCount) {
|
|
175
210
|
let options = _options || {};
|
|
176
211
|
let inheritedThis = Object.create(options.connection || this.getContextValue('connection', this));
|
|
177
212
|
let lockMode = inheritedThis.getLockMode(options.lock);
|
|
@@ -198,15 +233,33 @@ class PostgreSQLConnection extends SQLConnectionBase {
|
|
|
198
233
|
}
|
|
199
234
|
|
|
200
235
|
if (!inheritedThis.inTransaction) {
|
|
201
|
-
client = inheritedThis.inTransaction = await inheritedThis.
|
|
236
|
+
client = inheritedThis.inTransaction = await inheritedThis.getPoolConnection();
|
|
237
|
+
|
|
238
|
+
let beginSuccess = false;
|
|
202
239
|
|
|
203
240
|
try {
|
|
204
241
|
await inheritedThis.query(`BEGIN${(options.beginArguments) ? ` ${options.beginArguments}` : ''}`, options, client);
|
|
205
|
-
|
|
242
|
+
beginSuccess = true;
|
|
243
|
+
|
|
244
|
+
if (lockStatement) {
|
|
245
|
+
console.log('LOCK STATEMENT: ', lockStatement);
|
|
206
246
|
await inheritedThis.query(lockStatement, options, client);
|
|
247
|
+
}
|
|
207
248
|
|
|
208
249
|
// TODO: Need to handle "busy" error
|
|
209
250
|
} catch (error) {
|
|
251
|
+
if (beginSuccess)
|
|
252
|
+
await inheritedThis.query('ROLLBACK', options, client);
|
|
253
|
+
|
|
254
|
+
// Transaction timeout (deadlock)
|
|
255
|
+
if (error.query && (/LOCK TABLE/).test(error.query.text)) {
|
|
256
|
+
let retryCount = _retryCount || 0;
|
|
257
|
+
if (retryCount < 5) {
|
|
258
|
+
await client.release();
|
|
259
|
+
return this.transaction(callback, _options, retryCount + 1);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
210
263
|
await client.release();
|
|
211
264
|
throw error;
|
|
212
265
|
}
|
|
@@ -221,7 +274,7 @@ class PostgreSQLConnection extends SQLConnectionBase {
|
|
|
221
274
|
}
|
|
222
275
|
|
|
223
276
|
try {
|
|
224
|
-
let result = await inheritedThis.createContext(callback, inheritedThis, inheritedThis);
|
|
277
|
+
let result = await await inheritedThis.createContext(callback, inheritedThis, inheritedThis);
|
|
225
278
|
|
|
226
279
|
if (savePointName)
|
|
227
280
|
await inheritedThis.query(`RELEASE SAVEPOINT ${savePointName}`, options, client);
|