@maestro-js/db 1.0.0-alpha.2 → 1.0.0-alpha.21
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/dist/index.d.ts +7 -1
- package/dist/index.js +46 -16
- package/package.json +9 -6
package/dist/index.d.ts
CHANGED
|
@@ -63,6 +63,7 @@ interface MysqlDbDriverConfig {
|
|
|
63
63
|
connectionLimit?: number;
|
|
64
64
|
debug?: boolean;
|
|
65
65
|
multipleStatements?: boolean;
|
|
66
|
+
maxExecutionTime?: number;
|
|
66
67
|
ssl?: string | (tls.SecureContextOptions & {
|
|
67
68
|
rejectUnauthorized?: boolean | undefined;
|
|
68
69
|
}) | undefined;
|
|
@@ -84,6 +85,10 @@ interface MysqlDbDriverConfig {
|
|
|
84
85
|
queryId: string;
|
|
85
86
|
connectDurationMs: number;
|
|
86
87
|
error: unknown;
|
|
88
|
+
} | {
|
|
89
|
+
event: 'poolError';
|
|
90
|
+
activeConnections: number;
|
|
91
|
+
error: unknown;
|
|
87
92
|
}
|
|
88
93
|
]>;
|
|
89
94
|
queryLogger?: Log.LogFunctions<MysqlDbDriverLogMessageData>;
|
|
@@ -93,6 +98,7 @@ declare function mysqlDbDriver(config: MysqlDbDriverConfig): DbDriver;
|
|
|
93
98
|
type KeysWithFallback = keyof Db.Provider.Keys extends never ? {
|
|
94
99
|
default: unknown;
|
|
95
100
|
} : Db.Provider.Keys;
|
|
101
|
+
type DbMysqlLogMessage = MysqlDbDriverLogMessageData;
|
|
96
102
|
/**
|
|
97
103
|
* Creates a new connection pool using the supplied options.
|
|
98
104
|
*/
|
|
@@ -207,7 +213,7 @@ declare namespace Db {
|
|
|
207
213
|
namespace drivers {
|
|
208
214
|
namespace mysql {
|
|
209
215
|
/** Log event data emitted by the MySQL driver for query and transaction lifecycle events */
|
|
210
|
-
type MysqlDbDriverLogMessageData =
|
|
216
|
+
type MysqlDbDriverLogMessageData = DbMysqlLogMessage;
|
|
211
217
|
}
|
|
212
218
|
}
|
|
213
219
|
namespace Provider {
|
package/dist/index.js
CHANGED
|
@@ -11,10 +11,9 @@ import { randomUUID } from "crypto";
|
|
|
11
11
|
import "tls";
|
|
12
12
|
import { Context } from "@maestro-js/context";
|
|
13
13
|
import { Helpers } from "@maestro-js/helpers";
|
|
14
|
-
import { Log } from "@maestro-js/log";
|
|
15
14
|
function mysqlDbDriver(config) {
|
|
16
|
-
const connectionLogger = config?.connectionLogger
|
|
17
|
-
const queryLogger = config?.queryLogger
|
|
15
|
+
const connectionLogger = config?.connectionLogger;
|
|
16
|
+
const queryLogger = config?.queryLogger;
|
|
18
17
|
const transactionContext = new AsyncLocalStorage();
|
|
19
18
|
function getPoolConnection() {
|
|
20
19
|
return new Promise((resolve, reject) => {
|
|
@@ -95,9 +94,13 @@ function mysqlDbDriver(config) {
|
|
|
95
94
|
database: config.database,
|
|
96
95
|
port: config.port,
|
|
97
96
|
connectionLimit: config.connectionLimit ?? 10,
|
|
98
|
-
connectTimeout:
|
|
97
|
+
connectTimeout: 1e4,
|
|
99
98
|
waitForConnections: true,
|
|
100
|
-
queueLimit:
|
|
99
|
+
queueLimit: 100,
|
|
100
|
+
maxIdle: 10,
|
|
101
|
+
idleTimeout: 6e4,
|
|
102
|
+
enableKeepAlive: true,
|
|
103
|
+
keepAliveInitialDelay: 1e4,
|
|
101
104
|
timezone: "Z",
|
|
102
105
|
debug: false,
|
|
103
106
|
multipleStatements: config.multipleStatements,
|
|
@@ -110,13 +113,35 @@ function mysqlDbDriver(config) {
|
|
|
110
113
|
decimalNumbers: true
|
|
111
114
|
});
|
|
112
115
|
let connectionCount = 0;
|
|
116
|
+
let activeConnections = 0;
|
|
117
|
+
pool.on("acquire", function() {
|
|
118
|
+
activeConnections++;
|
|
119
|
+
});
|
|
120
|
+
pool.on("release", function() {
|
|
121
|
+
activeConnections--;
|
|
122
|
+
});
|
|
113
123
|
pool.on("connection", function(connection) {
|
|
114
124
|
connectionCount++;
|
|
115
|
-
connectionLogger
|
|
125
|
+
connectionLogger?.info({
|
|
116
126
|
event: "newConnection",
|
|
117
127
|
connectionCount,
|
|
118
128
|
connectionThreadId: connection.threadId
|
|
119
129
|
});
|
|
130
|
+
if (config.maxExecutionTime) {
|
|
131
|
+
connection.query(mysql.format("SET SESSION max_execution_time = ?", [config.maxExecutionTime]), (err) => {
|
|
132
|
+
if (err) {
|
|
133
|
+
console.error("Failed to set max_execution_time:", err);
|
|
134
|
+
connection.destroy();
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
pool.on("error", function(err) {
|
|
140
|
+
connectionLogger?.error({
|
|
141
|
+
event: "poolError",
|
|
142
|
+
activeConnections,
|
|
143
|
+
error: err
|
|
144
|
+
});
|
|
120
145
|
});
|
|
121
146
|
async function transaction(callback) {
|
|
122
147
|
const connection = await _getConnection();
|
|
@@ -179,7 +204,7 @@ function mysqlDbDriver(config) {
|
|
|
179
204
|
const transactionStartTime = (/* @__PURE__ */ new Date()).getTime();
|
|
180
205
|
try {
|
|
181
206
|
await connection.beginTransaction();
|
|
182
|
-
queryLogger
|
|
207
|
+
queryLogger?.info({
|
|
183
208
|
event: "transactionStarted",
|
|
184
209
|
transactionId: contextValue.currentTransaction.id
|
|
185
210
|
});
|
|
@@ -191,7 +216,7 @@ function mysqlDbDriver(config) {
|
|
|
191
216
|
}
|
|
192
217
|
await contextValue.commit();
|
|
193
218
|
const duration = (/* @__PURE__ */ new Date()).getTime() - transactionStartTime;
|
|
194
|
-
queryLogger
|
|
219
|
+
queryLogger?.info({
|
|
195
220
|
event: "transactionCompleted",
|
|
196
221
|
transactionId: contextValue.currentTransaction.id,
|
|
197
222
|
durationMs: duration
|
|
@@ -204,7 +229,7 @@ function mysqlDbDriver(config) {
|
|
|
204
229
|
);
|
|
205
230
|
await connection.rollback();
|
|
206
231
|
const duration = (/* @__PURE__ */ new Date()).getTime() - transactionStartTime;
|
|
207
|
-
queryLogger
|
|
232
|
+
queryLogger?.info({
|
|
208
233
|
event: "transactionFailed",
|
|
209
234
|
transactionId: contextValue.currentTransaction.id,
|
|
210
235
|
durationMs: duration,
|
|
@@ -222,13 +247,13 @@ function mysqlDbDriver(config) {
|
|
|
222
247
|
}
|
|
223
248
|
async function getConnectionForQuery(queryId) {
|
|
224
249
|
const connectStartTime = (/* @__PURE__ */ new Date()).getTime();
|
|
225
|
-
connectionLogger
|
|
250
|
+
connectionLogger?.info({
|
|
226
251
|
event: "connectionAcquisitionStarted",
|
|
227
252
|
queryId
|
|
228
253
|
});
|
|
229
254
|
try {
|
|
230
255
|
const connection = await _getConnection();
|
|
231
|
-
connectionLogger
|
|
256
|
+
connectionLogger?.info({
|
|
232
257
|
event: "connectionAcquisitionCompleted",
|
|
233
258
|
queryId,
|
|
234
259
|
connectionId: connection.id,
|
|
@@ -236,7 +261,7 @@ function mysqlDbDriver(config) {
|
|
|
236
261
|
});
|
|
237
262
|
return connection;
|
|
238
263
|
} catch (e) {
|
|
239
|
-
connectionLogger
|
|
264
|
+
connectionLogger?.error({
|
|
240
265
|
event: "connectionAcquisitionFailed",
|
|
241
266
|
queryId,
|
|
242
267
|
connectDurationMs: (/* @__PURE__ */ new Date()).getTime() - connectStartTime,
|
|
@@ -254,7 +279,7 @@ function mysqlDbDriver(config) {
|
|
|
254
279
|
const formatted = mysql.format(query, params);
|
|
255
280
|
const queryStartTime = (/* @__PURE__ */ new Date()).getTime();
|
|
256
281
|
const context = Context.getStore();
|
|
257
|
-
queryLogger
|
|
282
|
+
queryLogger?.info({
|
|
258
283
|
event: "queryStarted",
|
|
259
284
|
queryId,
|
|
260
285
|
formattedQuery: formatted,
|
|
@@ -272,7 +297,7 @@ function mysqlDbDriver(config) {
|
|
|
272
297
|
Context.runWith(context, () => {
|
|
273
298
|
if (!streamError) {
|
|
274
299
|
const duration = (/* @__PURE__ */ new Date()).getTime() - queryStartTime;
|
|
275
|
-
queryLogger
|
|
300
|
+
queryLogger?.info({
|
|
276
301
|
event: "queryCompleted",
|
|
277
302
|
queryId,
|
|
278
303
|
durationMs: duration,
|
|
@@ -288,7 +313,7 @@ function mysqlDbDriver(config) {
|
|
|
288
313
|
queryStream.on("error", (error) => {
|
|
289
314
|
Context.runWith(context, () => {
|
|
290
315
|
streamError = error;
|
|
291
|
-
queryLogger
|
|
316
|
+
queryLogger?.error({
|
|
292
317
|
event: "queryFailed",
|
|
293
318
|
queryId,
|
|
294
319
|
durationMs: (/* @__PURE__ */ new Date()).getTime() - queryStartTime,
|
|
@@ -392,6 +417,9 @@ function mysqlDbDriver(config) {
|
|
|
392
417
|
}
|
|
393
418
|
};
|
|
394
419
|
}
|
|
420
|
+
function isConnectionError(err) {
|
|
421
|
+
return "code" in err && err.code === "ECONNRESET" || "code" in err && err.code === "ECONNREFUSED" || "code" in err && err.code === "ETIMEDOUT" || "code" in err && err.code === "PROTOCOL_CONNECTION_LOST";
|
|
422
|
+
}
|
|
395
423
|
async function execute(query, params = []) {
|
|
396
424
|
const queryId = randomUUID();
|
|
397
425
|
const isInTransaction = !!transactionContext.getStore();
|
|
@@ -427,7 +455,9 @@ function mysqlDbDriver(config) {
|
|
|
427
455
|
{
|
|
428
456
|
maxAttempts: 3,
|
|
429
457
|
delay: 0,
|
|
430
|
-
shouldRetry: (err) => "code" in err && err.code === "ER_LOCK_DEADLOCK" && !isInTransaction || "code" in err && err.code === "ER_LOCK_WAIT_TIMEOUT" ||
|
|
458
|
+
shouldRetry: (err) => "code" in err && err.code === "ER_LOCK_DEADLOCK" && !isInTransaction || "code" in err && err.code === "ER_LOCK_WAIT_TIMEOUT" || // Retry on connection errors so queries can recover after a failover severs connections.
|
|
459
|
+
// Not safe inside a transaction — the whole transaction must be retried by the caller.
|
|
460
|
+
isConnectionError(err) && !isInTransaction || err instanceof Error && err.message.includes("Please retry") || err instanceof Error && err.message.includes("Try restarting transaction") && !isInTransaction
|
|
431
461
|
}
|
|
432
462
|
);
|
|
433
463
|
return results;
|
package/package.json
CHANGED
|
@@ -11,15 +11,18 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"iso-fns2": "npm:iso-fns@2.0.0-alpha.26",
|
|
13
13
|
"mysql2": "^3.15.3",
|
|
14
|
-
"@maestro-js/context": "1.0.0-alpha.
|
|
15
|
-
"@maestro-js/helpers": "1.0.0-alpha.
|
|
16
|
-
"@maestro-js/
|
|
17
|
-
|
|
14
|
+
"@maestro-js/context": "1.0.0-alpha.21",
|
|
15
|
+
"@maestro-js/helpers": "1.0.0-alpha.21",
|
|
16
|
+
"@maestro-js/service-registry": "1.0.0-alpha.21"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"@maestro-js/log": "1.0.0-alpha.21"
|
|
18
20
|
},
|
|
19
21
|
"devDependencies": {
|
|
20
|
-
"@types/node": "^22.19.11"
|
|
22
|
+
"@types/node": "^22.19.11",
|
|
23
|
+
"@maestro-js/log": "1.0.0-alpha.21"
|
|
21
24
|
},
|
|
22
|
-
"version": "1.0.0-alpha.
|
|
25
|
+
"version": "1.0.0-alpha.21",
|
|
23
26
|
"publishConfig": {
|
|
24
27
|
"access": "restricted"
|
|
25
28
|
},
|