@aetherframework/database 1.0.9 → 1.1.0
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/package.json +1 -2
- package/src/DatabaseManager.js +0 -565
- package/src/core/ConnectionManager.js +0 -351
- package/src/core/DatabaseFactory.js +0 -188
- package/src/core/MongoQueryBuilder.js +0 -576
- package/src/core/PluginManager.js +0 -968
- package/src/core/QueryBuilder.js +0 -4398
- package/src/core/TransactionManager.js +0 -40
- package/src/drivers/clickhouse-driver.js +0 -272
- package/src/drivers/index.js +0 -273
- package/src/drivers/mongodb-driver.js +0 -87
- package/src/drivers/mssql-driver.js +0 -117
- package/src/drivers/mysql-driver.js +0 -169
- package/src/drivers/oracle-driver.js +0 -101
- package/src/drivers/postgres-driver.js +0 -234
- package/src/drivers/redis-driver.js +0 -52
- package/src/drivers/sqlite-driver.js +0 -67
- package/src/middleware/connection-pool.js +0 -455
- package/src/middleware/performance-monitor.js +0 -652
- package/src/middleware/query-cache.js +0 -500
- package/src/middleware/query-logger.js +0 -262
- package/src/plugins/AuditPlugin.js +0 -447
- package/src/plugins/BasePlugin.js +0 -418
- package/src/plugins/BatchOperationPlugin.js +0 -165
- package/src/plugins/CachePlugin.js +0 -407
- package/src/plugins/CtePlugin.js +0 -523
- package/src/plugins/DistributedPlugin.js +0 -543
- package/src/plugins/EncryptionPlugin.js +0 -211
- package/src/plugins/FullTextSearchPlugin.js +0 -164
- package/src/plugins/GeospatialPlugin.js +0 -219
- package/src/plugins/GraphQLPlugin.js +0 -162
- package/src/plugins/HookPlugin.js +0 -211
- package/src/plugins/JsonPlugin.js +0 -366
- package/src/plugins/OptimisticLockPlugin.js +0 -374
- package/src/plugins/PerformancePlugin.js +0 -175
- package/src/plugins/ResiliencePlugin.js +0 -114
- package/src/plugins/ShardingPlugin.js +0 -227
- package/src/plugins/SoftDeletePlugin.js +0 -258
- package/src/plugins/SyncPlugin.js +0 -373
- package/src/plugins/VersioningPlugin.js +0 -314
- package/src/plugins/WindowFunctionPlugin.js +0 -343
- package/src/utils/config-loader.js +0 -632
- package/src/utils/error-handler.js +0 -724
- package/src/utils/migration-runner.js +0 -1066
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license MIT
|
|
3
|
-
* Copyright (c) 2026-present AetherFramework Contributors.
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
* @module @aetherframework/database/drivers/sqlite-driver
|
|
6
|
-
*/
|
|
7
|
-
import sqlite3 from 'sqlite3';
|
|
8
|
-
import { open } from 'sqlite';
|
|
9
|
-
|
|
10
|
-
class SQLiteDriver {
|
|
11
|
-
constructor(config) {
|
|
12
|
-
this.config = config;
|
|
13
|
-
this.db = null;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async connect(config) {
|
|
17
|
-
const db = await open({
|
|
18
|
-
filename: config.database === ':memory:' ? ':memory:' : config.database,
|
|
19
|
-
driver: sqlite3.Database,
|
|
20
|
-
mode: config.mode === 'memory' ? sqlite3.OPEN_MEMORY : sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE
|
|
21
|
-
});
|
|
22
|
-
this.db = db;
|
|
23
|
-
return db;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async query(connection, sql, params = []) {
|
|
27
|
-
const rows = await connection.all(sql, params);
|
|
28
|
-
const info = await connection.run(sql, params);
|
|
29
|
-
return {
|
|
30
|
-
rows,
|
|
31
|
-
rowCount: rows.length,
|
|
32
|
-
lastID: info.lastID,
|
|
33
|
-
changes: info.changes
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async execute(connection, sql, params = []) {
|
|
38
|
-
const result = await connection.run(sql, params);
|
|
39
|
-
return {
|
|
40
|
-
lastID: result.lastID,
|
|
41
|
-
changes: result.changes
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async beginTransaction(connection) {
|
|
46
|
-
await connection.run('BEGIN TRANSACTION');
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async commitTransaction(connection) {
|
|
50
|
-
await connection.run('COMMIT');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async rollbackTransaction(connection) {
|
|
54
|
-
await connection.run('ROLLBACK');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async close(connection) {
|
|
58
|
-
await connection.close();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async healthCheck(connection) {
|
|
62
|
-
const result = await connection.get('SELECT 1 as health');
|
|
63
|
-
return result.health === 1;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export default SQLiteDriver;
|
|
@@ -1,455 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license MIT
|
|
3
|
-
* Copyright (c) 2026-present AetherFramework Contributors.
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
* @module @aetherframework/database/middleware/connection-pool
|
|
6
|
-
*/
|
|
7
|
-
import { EventEmitter } from 'events';
|
|
8
|
-
|
|
9
|
-
class ConnectionPoolMiddleware extends EventEmitter {
|
|
10
|
-
constructor(options = {}) {
|
|
11
|
-
super();
|
|
12
|
-
this.options = {
|
|
13
|
-
maxConnections: options.maxConnections || 10,
|
|
14
|
-
minConnections: options.minConnections || 2,
|
|
15
|
-
idleTimeout: options.idleTimeout || 30000, // ms
|
|
16
|
-
acquireTimeout: options.acquireTimeout || 10000, // ms
|
|
17
|
-
evictionRunInterval: options.evictionRunInterval || 60000, // ms
|
|
18
|
-
testOnBorrow: options.testOnBorrow !== false,
|
|
19
|
-
testOnReturn: options.testOnReturn !== false,
|
|
20
|
-
...options
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
this.pool = new Map();
|
|
24
|
-
this.activeConnections = new Set();
|
|
25
|
-
this.waitingQueue = [];
|
|
26
|
-
this.stats = {
|
|
27
|
-
totalConnections: 0,
|
|
28
|
-
activeConnections: 0,
|
|
29
|
-
idleConnections: 0,
|
|
30
|
-
waitingClients: 0,
|
|
31
|
-
connectionCreations: 0,
|
|
32
|
-
connectionDestructions: 0,
|
|
33
|
-
connectionTimeouts: 0,
|
|
34
|
-
connectionErrors: 0
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
this.startEvictionTimer();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Get a connection from pool
|
|
42
|
-
* @param {string} connectionName - Connection name
|
|
43
|
-
* @param {Function} createConnection - Function to create new connection
|
|
44
|
-
* @returns {Promise<Object>} Database connection
|
|
45
|
-
*/
|
|
46
|
-
async getConnection(connectionName, createConnection) {
|
|
47
|
-
const poolKey = connectionName;
|
|
48
|
-
|
|
49
|
-
// Check if we have idle connections
|
|
50
|
-
if (this.pool.has(poolKey) && this.pool.get(poolKey).length > 0) {
|
|
51
|
-
const connections = this.pool.get(poolKey);
|
|
52
|
-
const connection = connections.pop();
|
|
53
|
-
|
|
54
|
-
// Test connection if enabled
|
|
55
|
-
if (this.options.testOnBorrow) {
|
|
56
|
-
try {
|
|
57
|
-
await this.testConnection(connection);
|
|
58
|
-
} catch (error) {
|
|
59
|
-
this.stats.connectionErrors++;
|
|
60
|
-
this.emit('connection-test-failed', { connectionName, error });
|
|
61
|
-
// Remove bad connection and create new one
|
|
62
|
-
this.stats.connectionDestructions++;
|
|
63
|
-
return this.createNewConnection(connectionName, createConnection);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
this.activeConnections.add(connection);
|
|
68
|
-
this.stats.activeConnections++;
|
|
69
|
-
this.stats.idleConnections--;
|
|
70
|
-
|
|
71
|
-
this.emit('connection-acquired', {
|
|
72
|
-
connectionName,
|
|
73
|
-
fromPool: true,
|
|
74
|
-
activeConnections: this.stats.activeConnections,
|
|
75
|
-
idleConnections: this.stats.idleConnections
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
return connection;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Check if we can create new connection
|
|
82
|
-
if (this.stats.totalConnections < this.options.maxConnections) {
|
|
83
|
-
const connection = await this.createNewConnection(connectionName, createConnection);
|
|
84
|
-
this.activeConnections.add(connection);
|
|
85
|
-
this.stats.activeConnections++;
|
|
86
|
-
|
|
87
|
-
this.emit('connection-created', {
|
|
88
|
-
connectionName,
|
|
89
|
-
activeConnections: this.stats.activeConnections,
|
|
90
|
-
totalConnections: this.stats.totalConnections
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
return connection;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Wait for connection to become available
|
|
97
|
-
return new Promise((resolve, reject) => {
|
|
98
|
-
const waitStartTime = Date.now();
|
|
99
|
-
const timeoutId = setTimeout(() => {
|
|
100
|
-
const index = this.waitingQueue.findIndex(item => item.resolve === resolve);
|
|
101
|
-
if (index !== -1) {
|
|
102
|
-
this.waitingQueue.splice(index, 1);
|
|
103
|
-
this.stats.waitingClients--;
|
|
104
|
-
this.stats.connectionTimeouts++;
|
|
105
|
-
|
|
106
|
-
this.emit('connection-timeout', {
|
|
107
|
-
connectionName,
|
|
108
|
-
waitTime: Date.now() - waitStartTime,
|
|
109
|
-
waitingClients: this.stats.waitingClients
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
reject(new Error(`Connection pool timeout after ${this.options.acquireTimeout}ms`));
|
|
113
|
-
}
|
|
114
|
-
}, this.options.acquireTimeout);
|
|
115
|
-
|
|
116
|
-
this.waitingQueue.push({
|
|
117
|
-
connectionName,
|
|
118
|
-
resolve: async () => {
|
|
119
|
-
clearTimeout(timeoutId);
|
|
120
|
-
try {
|
|
121
|
-
const connection = await this.getConnection(connectionName, createConnection);
|
|
122
|
-
resolve(connection);
|
|
123
|
-
} catch (error) {
|
|
124
|
-
reject(error);
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
reject,
|
|
128
|
-
timestamp: Date.now()
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
this.stats.waitingClients++;
|
|
132
|
-
this.emit('connection-waiting', {
|
|
133
|
-
connectionName,
|
|
134
|
-
waitingClients: this.stats.waitingClients
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Release connection back to pool
|
|
141
|
-
* @param {string} connectionName - Connection name
|
|
142
|
-
* @param {Object} connection - Database connection
|
|
143
|
-
*/
|
|
144
|
-
async releaseConnection(connectionName, connection) {
|
|
145
|
-
if (!this.activeConnections.has(connection)) {
|
|
146
|
-
this.emit('connection-not-active', { connectionName });
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Test connection if enabled
|
|
151
|
-
if (this.options.testOnReturn) {
|
|
152
|
-
try {
|
|
153
|
-
await this.testConnection(connection);
|
|
154
|
-
} catch (error) {
|
|
155
|
-
this.stats.connectionErrors++;
|
|
156
|
-
this.emit('connection-test-failed', { connectionName, error });
|
|
157
|
-
// Destroy bad connection
|
|
158
|
-
await this.destroyConnection(connectionName, connection);
|
|
159
|
-
this.activeConnections.delete(connection);
|
|
160
|
-
this.stats.activeConnections--;
|
|
161
|
-
this.stats.totalConnections--;
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Add connection back to pool
|
|
167
|
-
if (!this.pool.has(connectionName)) {
|
|
168
|
-
this.pool.set(connectionName, []);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
this.pool.get(connectionName).push({
|
|
172
|
-
connection,
|
|
173
|
-
lastUsed: Date.now()
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
this.activeConnections.delete(connection);
|
|
177
|
-
this.stats.activeConnections--;
|
|
178
|
-
this.stats.idleConnections++;
|
|
179
|
-
|
|
180
|
-
// Check waiting queue
|
|
181
|
-
if (this.waitingQueue.length > 0) {
|
|
182
|
-
const nextRequest = this.waitingQueue.shift();
|
|
183
|
-
this.stats.waitingClients--;
|
|
184
|
-
nextRequest.resolve();
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
this.emit('connection-released', {
|
|
188
|
-
connectionName,
|
|
189
|
-
activeConnections: this.stats.activeConnections,
|
|
190
|
-
idleConnections: this.stats.idleConnections,
|
|
191
|
-
waitingClients: this.stats.waitingClients
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Create new connection
|
|
197
|
-
* @param {string} connectionName - Connection name
|
|
198
|
-
* @param {Function} createConnection - Function to create new connection
|
|
199
|
-
* @returns {Promise<Object>} New connection
|
|
200
|
-
*/
|
|
201
|
-
async createNewConnection(connectionName, createConnection) {
|
|
202
|
-
try {
|
|
203
|
-
const connection = await createConnection();
|
|
204
|
-
this.stats.totalConnections++;
|
|
205
|
-
this.stats.connectionCreations++;
|
|
206
|
-
|
|
207
|
-
this.emit('connection-created', {
|
|
208
|
-
connectionName,
|
|
209
|
-
activeConnections: this.stats.activeConnections,
|
|
210
|
-
totalConnections: this.stats.totalConnections
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
return connection;
|
|
214
|
-
} catch (error) {
|
|
215
|
-
this.stats.connectionErrors++;
|
|
216
|
-
this.emit('connection-creation-error', { connectionName, error });
|
|
217
|
-
throw error;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Destroy connection
|
|
223
|
-
* @param {string} connectionName - Connection name
|
|
224
|
-
* @param {Object} connection - Database connection
|
|
225
|
-
*/
|
|
226
|
-
async destroyConnection(connectionName, connection) {
|
|
227
|
-
try {
|
|
228
|
-
if (typeof connection.close === 'function') {
|
|
229
|
-
await connection.close();
|
|
230
|
-
} else if (typeof connection.end === 'function') {
|
|
231
|
-
await connection.end();
|
|
232
|
-
} else if (typeof connection.destroy === 'function') {
|
|
233
|
-
connection.destroy();
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
this.stats.connectionDestructions++;
|
|
237
|
-
this.emit('connection-destroyed', { connectionName });
|
|
238
|
-
} catch (error) {
|
|
239
|
-
this.stats.connectionErrors++;
|
|
240
|
-
this.emit('connection-destruction-error', { connectionName, error });
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Test connection health
|
|
246
|
-
* @param {Object} connection - Database connection
|
|
247
|
-
* @returns {Promise<boolean>} True if connection is healthy
|
|
248
|
-
*/
|
|
249
|
-
async testConnection(connection) {
|
|
250
|
-
// Try to execute a simple query to test connection
|
|
251
|
-
if (typeof connection.query === 'function') {
|
|
252
|
-
try {
|
|
253
|
-
await connection.query('SELECT 1');
|
|
254
|
-
return true;
|
|
255
|
-
} catch (error) {
|
|
256
|
-
return false;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// For connections without query method, assume they're healthy
|
|
261
|
-
return true;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Start eviction timer
|
|
266
|
-
*/
|
|
267
|
-
startEvictionTimer() {
|
|
268
|
-
setInterval(() => {
|
|
269
|
-
this.evictIdleConnections();
|
|
270
|
-
}, this.options.evictionRunInterval);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Evict idle connections
|
|
275
|
-
*/
|
|
276
|
-
async evictIdleConnections() {
|
|
277
|
-
const now = Date.now();
|
|
278
|
-
|
|
279
|
-
for (const [connectionName, connections] of this.pool.entries()) {
|
|
280
|
-
const activeConnections = [];
|
|
281
|
-
const idleConnections = [];
|
|
282
|
-
const toDestroy = [];
|
|
283
|
-
|
|
284
|
-
for (const connInfo of connections) {
|
|
285
|
-
const idleTime = now - connInfo.lastUsed;
|
|
286
|
-
|
|
287
|
-
if (idleTime > this.options.idleTimeout) {
|
|
288
|
-
toDestroy.push(connInfo);
|
|
289
|
-
} else if (this.activeConnections.has(connInfo.connection)) {
|
|
290
|
-
activeConnections.push(connInfo);
|
|
291
|
-
} else {
|
|
292
|
-
idleConnections.push(connInfo);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// Destroy idle connections that exceed idle timeout
|
|
297
|
-
for (const connInfo of toDestroy) {
|
|
298
|
-
await this.destroyConnection(connectionName, connInfo.connection);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Update pool with remaining connections
|
|
302
|
-
this.pool.set(connectionName, idleConnections);
|
|
303
|
-
this.stats.idleConnections = idleConnections.length;
|
|
304
|
-
this.stats.activeConnections = activeConnections.length;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Get pool statistics
|
|
310
|
-
* @returns {Object} Pool statistics
|
|
311
|
-
*/
|
|
312
|
-
getStats() {
|
|
313
|
-
const poolStats = {};
|
|
314
|
-
for (const [connectionName, connections] of this.pool.entries()) {
|
|
315
|
-
poolStats[connectionName] = {
|
|
316
|
-
idleConnections: connections.length,
|
|
317
|
-
activeConnections: Array.from(this.activeConnections).filter(conn =>
|
|
318
|
-
this.getConnectionName(conn) === connectionName
|
|
319
|
-
).length
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return {
|
|
324
|
-
...this.stats,
|
|
325
|
-
poolStats,
|
|
326
|
-
waitingQueueSize: this.waitingQueue.length,
|
|
327
|
-
evictionRunInterval: this.options.evictionRunInterval,
|
|
328
|
-
idleTimeout: this.options.idleTimeout,
|
|
329
|
-
acquireTimeout: this.options.acquireTimeout,
|
|
330
|
-
maxConnections: this.options.maxConnections,
|
|
331
|
-
minConnections: this.options.minConnections,
|
|
332
|
-
testOnBorrow: this.options.testOnBorrow,
|
|
333
|
-
testOnReturn: this.options.testOnReturn,
|
|
334
|
-
timestamp: new Date().toISOString()
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* Get connection name from connection object
|
|
340
|
-
* @param {Object} connection - Database connection
|
|
341
|
-
* @returns {string} Connection name
|
|
342
|
-
*/
|
|
343
|
-
getConnectionName(connection) {
|
|
344
|
-
for (const [name, connections] of this.pool.entries()) {
|
|
345
|
-
if (connections.some(connInfo => connInfo.connection === connection)) {
|
|
346
|
-
return name;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
return 'unknown';
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Close all connections in pool
|
|
354
|
-
* @returns {Promise<void>}
|
|
355
|
-
*/
|
|
356
|
-
async closeAll() {
|
|
357
|
-
const closePromises = [];
|
|
358
|
-
|
|
359
|
-
// Close all idle connections
|
|
360
|
-
for (const [connectionName, connections] of this.pool.entries()) {
|
|
361
|
-
for (const connInfo of connections) {
|
|
362
|
-
closePromises.push(this.destroyConnection(connectionName, connInfo.connection));
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// Close all active connections
|
|
367
|
-
for (const connection of this.activeConnections) {
|
|
368
|
-
const connectionName = this.getConnectionName(connection);
|
|
369
|
-
closePromises.push(this.destroyConnection(connectionName, connection));
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// Clear waiting queue
|
|
373
|
-
for (const request of this.waitingQueue) {
|
|
374
|
-
request.reject(new Error('Connection pool closed'));
|
|
375
|
-
}
|
|
376
|
-
this.waitingQueue = [];
|
|
377
|
-
|
|
378
|
-
await Promise.allSettled(closePromises);
|
|
379
|
-
|
|
380
|
-
this.pool.clear();
|
|
381
|
-
this.activeConnections.clear();
|
|
382
|
-
this.stats = {
|
|
383
|
-
totalConnections: 0,
|
|
384
|
-
activeConnections: 0,
|
|
385
|
-
idleConnections: 0,
|
|
386
|
-
waitingClients: 0,
|
|
387
|
-
connectionCreations: 0,
|
|
388
|
-
connectionDestructions: 0,
|
|
389
|
-
connectionTimeouts: 0,
|
|
390
|
-
connectionErrors: 0
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
this.emit('pool-closed');
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Drain pool (stop accepting new connections)
|
|
398
|
-
* @returns {Promise<void>}
|
|
399
|
-
*/
|
|
400
|
-
async drain() {
|
|
401
|
-
this.options.maxConnections = 0;
|
|
402
|
-
|
|
403
|
-
// Wait for all active connections to be released
|
|
404
|
-
while (this.activeConnections.size > 0) {
|
|
405
|
-
await new Promise(resolve => setTimeout(resolve, 100));
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
// Close all idle connections
|
|
409
|
-
await this.closeAll();
|
|
410
|
-
|
|
411
|
-
this.emit('pool-drained');
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* Check if pool is healthy
|
|
416
|
-
* @returns {Object} Health status
|
|
417
|
-
*/
|
|
418
|
-
getHealth() {
|
|
419
|
-
const stats = this.getStats();
|
|
420
|
-
const isHealthy =
|
|
421
|
-
stats.connectionErrors < 10 &&
|
|
422
|
-
stats.connectionTimeouts < 5 &&
|
|
423
|
-
stats.waitingQueueSize < 20;
|
|
424
|
-
|
|
425
|
-
return {
|
|
426
|
-
healthy: isHealthy,
|
|
427
|
-
status: isHealthy ? 'healthy' : 'unhealthy',
|
|
428
|
-
issues: !isHealthy ? [
|
|
429
|
-
...(stats.connectionErrors >= 10 ? ['Too many connection errors'] : []),
|
|
430
|
-
...(stats.connectionTimeouts >= 5 ? ['Too many connection timeouts'] : []),
|
|
431
|
-
...(stats.waitingQueueSize >= 20 ? ['Too many waiting clients'] : [])
|
|
432
|
-
] : [],
|
|
433
|
-
stats
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
/**
|
|
438
|
-
* Reset pool statistics
|
|
439
|
-
*/
|
|
440
|
-
resetStats() {
|
|
441
|
-
this.stats = {
|
|
442
|
-
totalConnections: this.stats.totalConnections,
|
|
443
|
-
activeConnections: this.stats.activeConnections,
|
|
444
|
-
idleConnections: this.stats.idleConnections,
|
|
445
|
-
waitingClients: this.stats.waitingClients,
|
|
446
|
-
connectionCreations: 0,
|
|
447
|
-
connectionDestructions: 0,
|
|
448
|
-
connectionTimeouts: 0,
|
|
449
|
-
connectionErrors: 0
|
|
450
|
-
};
|
|
451
|
-
this.emit('stats-reset');
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
export default ConnectionPoolMiddleware;
|