@maestro-js/db 1.0.0-alpha.1 → 1.0.0-alpha.11

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 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>;
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 ?? Log.create();
17
- const queryLogger = config?.queryLogger ?? Log.create();
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: 60 * 60 * 1e3,
97
+ connectTimeout: 1e4,
99
98
  waitForConnections: true,
100
- queueLimit: 0,
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.info({
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.info({
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.info({
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.info({
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.info({
250
+ connectionLogger?.info({
226
251
  event: "connectionAcquisitionStarted",
227
252
  queryId
228
253
  });
229
254
  try {
230
255
  const connection = await _getConnection();
231
- connectionLogger.info({
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.error({
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.info({
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.info({
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.error({
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" || err instanceof Error && err.message.includes("Please retry") || err instanceof Error && err.message.includes("Try restarting transaction") && !isInTransaction
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.1",
15
- "@maestro-js/helpers": "1.0.0-alpha.1",
16
- "@maestro-js/log": "1.0.0-alpha.1",
17
- "@maestro-js/service-registry": "1.0.0-alpha.1"
14
+ "@maestro-js/helpers": "1.0.0-alpha.11",
15
+ "@maestro-js/service-registry": "1.0.0-alpha.11",
16
+ "@maestro-js/context": "1.0.0-alpha.11"
17
+ },
18
+ "peerDependencies": {
19
+ "@maestro-js/log": "1.0.0-alpha.11"
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.11"
21
24
  },
22
- "version": "1.0.0-alpha.1",
25
+ "version": "1.0.0-alpha.11",
23
26
  "publishConfig": {
24
27
  "access": "restricted"
25
28
  },