@spfn/core 0.2.0-beta.17 → 0.2.0-beta.18
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/db/index.js +52 -27
- package/dist/db/index.js.map +1 -1
- package/docs/server.md +76 -6
- package/package.json +1 -1
package/dist/db/index.js
CHANGED
|
@@ -503,6 +503,8 @@ var setMonitoringConfig = (config) => {
|
|
|
503
503
|
globalThis.__SPFN_DB_MONITORING__ = config;
|
|
504
504
|
};
|
|
505
505
|
var dbLogger3 = logger.child("@spfn/core:database");
|
|
506
|
+
var CLIENT_CLOSE_TIMEOUT = 5;
|
|
507
|
+
var isReconnecting = false;
|
|
506
508
|
async function testDatabaseConnection(db) {
|
|
507
509
|
await db.execute("SELECT 1");
|
|
508
510
|
}
|
|
@@ -514,8 +516,13 @@ async function performHealthCheck(getDatabase2) {
|
|
|
514
516
|
await testDatabaseConnection(read);
|
|
515
517
|
}
|
|
516
518
|
}
|
|
517
|
-
async function
|
|
518
|
-
|
|
519
|
+
async function closeClient(client) {
|
|
520
|
+
try {
|
|
521
|
+
await client.end({ timeout: CLIENT_CLOSE_TIMEOUT });
|
|
522
|
+
} catch {
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
async function reconnectAndRestore(options) {
|
|
519
526
|
const result = await createDatabaseFromEnv(options);
|
|
520
527
|
if (!result.write) {
|
|
521
528
|
return false;
|
|
@@ -524,15 +531,23 @@ async function reconnectAndRestore(options, closeDatabase2) {
|
|
|
524
531
|
if (result.read && result.read !== result.write) {
|
|
525
532
|
await testDatabaseConnection(result.read);
|
|
526
533
|
}
|
|
534
|
+
const oldWriteClient = getWriteClient();
|
|
535
|
+
const oldReadClient = getReadClient();
|
|
527
536
|
setWriteInstance(result.write);
|
|
528
537
|
setReadInstance(result.read);
|
|
529
538
|
setWriteClient(result.writeClient);
|
|
530
539
|
setReadClient(result.readClient);
|
|
531
540
|
const monConfig = buildMonitoringConfig(options?.monitoring);
|
|
532
541
|
setMonitoringConfig(monConfig);
|
|
542
|
+
if (oldWriteClient) {
|
|
543
|
+
closeClient(oldWriteClient);
|
|
544
|
+
}
|
|
545
|
+
if (oldReadClient && oldReadClient !== oldWriteClient) {
|
|
546
|
+
closeClient(oldReadClient);
|
|
547
|
+
}
|
|
533
548
|
return true;
|
|
534
549
|
}
|
|
535
|
-
function startHealthCheck(config, options, getDatabase2
|
|
550
|
+
function startHealthCheck(config, options, getDatabase2) {
|
|
536
551
|
const healthCheck = getHealthCheckInterval();
|
|
537
552
|
if (healthCheck) {
|
|
538
553
|
dbLogger3.debug("Health check already running");
|
|
@@ -543,47 +558,56 @@ function startHealthCheck(config, options, getDatabase2, closeDatabase2) {
|
|
|
543
558
|
reconnect: config.reconnect
|
|
544
559
|
});
|
|
545
560
|
const interval = setInterval(async () => {
|
|
561
|
+
if (isReconnecting) {
|
|
562
|
+
dbLogger3.debug("Health check skipped: reconnection in progress");
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
546
565
|
try {
|
|
547
566
|
await performHealthCheck(getDatabase2);
|
|
548
567
|
} catch (error) {
|
|
549
568
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
550
569
|
dbLogger3.error("Database health check failed", { error: message });
|
|
551
570
|
if (config.reconnect) {
|
|
552
|
-
await attemptReconnection(config, options
|
|
571
|
+
await attemptReconnection(config, options);
|
|
553
572
|
}
|
|
554
573
|
}
|
|
555
574
|
}, config.interval);
|
|
556
575
|
setHealthCheckInterval(interval);
|
|
557
576
|
}
|
|
558
|
-
async function attemptReconnection(config, options
|
|
577
|
+
async function attemptReconnection(config, options) {
|
|
578
|
+
isReconnecting = true;
|
|
559
579
|
dbLogger3.warn("Attempting database reconnection", {
|
|
560
580
|
maxRetries: config.maxRetries,
|
|
561
581
|
retryInterval: `${config.retryInterval}ms`
|
|
562
582
|
});
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
583
|
+
try {
|
|
584
|
+
for (let attempt = 1; attempt <= config.maxRetries; attempt++) {
|
|
585
|
+
try {
|
|
586
|
+
dbLogger3.debug(`Reconnection attempt ${attempt}/${config.maxRetries}`);
|
|
587
|
+
if (attempt > 1) {
|
|
588
|
+
await new Promise((resolve) => setTimeout(resolve, config.retryInterval));
|
|
589
|
+
}
|
|
590
|
+
const success = await reconnectAndRestore(options);
|
|
591
|
+
if (success) {
|
|
592
|
+
dbLogger3.info("Database reconnection successful", { attempt });
|
|
593
|
+
return;
|
|
594
|
+
} else {
|
|
595
|
+
dbLogger3.error(`Reconnection attempt ${attempt} failed: No write database instance created`);
|
|
596
|
+
}
|
|
597
|
+
} catch (error) {
|
|
598
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
599
|
+
dbLogger3.error(`Reconnection attempt ${attempt} failed`, {
|
|
600
|
+
error: message,
|
|
601
|
+
attempt,
|
|
602
|
+
maxRetries: config.maxRetries
|
|
603
|
+
});
|
|
568
604
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
dbLogger3.info("Database reconnection successful", { attempt });
|
|
572
|
-
return;
|
|
573
|
-
} else {
|
|
574
|
-
dbLogger3.error(`Reconnection attempt ${attempt} failed: No write database instance created`);
|
|
605
|
+
if (attempt === config.maxRetries) {
|
|
606
|
+
dbLogger3.error("Max reconnection attempts reached, will retry on next health check");
|
|
575
607
|
}
|
|
576
|
-
} catch (error) {
|
|
577
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
578
|
-
dbLogger3.error(`Reconnection attempt ${attempt} failed`, {
|
|
579
|
-
error: message,
|
|
580
|
-
attempt,
|
|
581
|
-
maxRetries: config.maxRetries
|
|
582
|
-
});
|
|
583
|
-
}
|
|
584
|
-
if (attempt === config.maxRetries) {
|
|
585
|
-
dbLogger3.error("Max reconnection attempts reached, giving up");
|
|
586
608
|
}
|
|
609
|
+
} finally {
|
|
610
|
+
isReconnecting = false;
|
|
587
611
|
}
|
|
588
612
|
}
|
|
589
613
|
function stopHealthCheck() {
|
|
@@ -593,6 +617,7 @@ function stopHealthCheck() {
|
|
|
593
617
|
setHealthCheckInterval(void 0);
|
|
594
618
|
dbLogger3.info("Database health check stopped");
|
|
595
619
|
}
|
|
620
|
+
isReconnecting = false;
|
|
596
621
|
}
|
|
597
622
|
|
|
598
623
|
// src/db/manager/manager.ts
|
|
@@ -742,7 +767,7 @@ async function initDatabase(options) {
|
|
|
742
767
|
);
|
|
743
768
|
const healthCheckConfig = buildHealthCheckConfig(options?.healthCheck);
|
|
744
769
|
if (healthCheckConfig.enabled) {
|
|
745
|
-
startHealthCheck(healthCheckConfig, options, getDatabase
|
|
770
|
+
startHealthCheck(healthCheckConfig, options, getDatabase);
|
|
746
771
|
}
|
|
747
772
|
const monConfig = buildMonitoringConfig(options?.monitoring);
|
|
748
773
|
setMonitoringConfig(monConfig);
|