@spfn/core 0.2.0-beta.17 → 0.2.0-beta.19
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/config/index.d.ts +39 -0
- package/dist/db/index.js +52 -27
- package/dist/db/index.js.map +1 -1
- package/dist/env/index.d.ts +1 -0
- package/dist/env/index.js +2 -1
- package/dist/env/index.js.map +1 -1
- package/docs/server.md +76 -6
- package/package.json +1 -1
package/dist/config/index.d.ts
CHANGED
|
@@ -34,6 +34,7 @@ declare const coreEnvSchema: {
|
|
|
34
34
|
examples: string[];
|
|
35
35
|
} & {
|
|
36
36
|
type: "string";
|
|
37
|
+
validator: (value: string) => string;
|
|
37
38
|
} & {
|
|
38
39
|
key: "DATABASE_URL";
|
|
39
40
|
};
|
|
@@ -45,6 +46,7 @@ declare const coreEnvSchema: {
|
|
|
45
46
|
examples: string[];
|
|
46
47
|
} & {
|
|
47
48
|
type: "string";
|
|
49
|
+
validator: (value: string) => string;
|
|
48
50
|
} & {
|
|
49
51
|
key: "DATABASE_WRITE_URL";
|
|
50
52
|
};
|
|
@@ -56,6 +58,7 @@ declare const coreEnvSchema: {
|
|
|
56
58
|
examples: string[];
|
|
57
59
|
} & {
|
|
58
60
|
type: "string";
|
|
61
|
+
validator: (value: string) => string;
|
|
59
62
|
} & {
|
|
60
63
|
key: "DATABASE_READ_URL";
|
|
61
64
|
};
|
|
@@ -226,6 +229,7 @@ declare const coreEnvSchema: {
|
|
|
226
229
|
examples: string[];
|
|
227
230
|
} & {
|
|
228
231
|
type: "string";
|
|
232
|
+
validator: (value: string) => string;
|
|
229
233
|
} & {
|
|
230
234
|
key: "DRIZZLE_SCHEMA_PATH";
|
|
231
235
|
};
|
|
@@ -236,6 +240,7 @@ declare const coreEnvSchema: {
|
|
|
236
240
|
examples: string[];
|
|
237
241
|
} & {
|
|
238
242
|
type: "string";
|
|
243
|
+
validator: (value: string) => string;
|
|
239
244
|
} & {
|
|
240
245
|
key: "DRIZZLE_OUT_DIR";
|
|
241
246
|
};
|
|
@@ -253,6 +258,7 @@ declare const coreEnvSchema: {
|
|
|
253
258
|
examples: string[];
|
|
254
259
|
} & {
|
|
255
260
|
type: "string";
|
|
261
|
+
validator: (value: string) => string;
|
|
256
262
|
} & {
|
|
257
263
|
key: "CACHE_URL";
|
|
258
264
|
};
|
|
@@ -264,6 +270,7 @@ declare const coreEnvSchema: {
|
|
|
264
270
|
examples: string[];
|
|
265
271
|
} & {
|
|
266
272
|
type: "string";
|
|
273
|
+
validator: (value: string) => string;
|
|
267
274
|
} & {
|
|
268
275
|
key: "CACHE_WRITE_URL";
|
|
269
276
|
};
|
|
@@ -275,6 +282,7 @@ declare const coreEnvSchema: {
|
|
|
275
282
|
examples: string[];
|
|
276
283
|
} & {
|
|
277
284
|
type: "string";
|
|
285
|
+
validator: (value: string) => string;
|
|
278
286
|
} & {
|
|
279
287
|
key: "CACHE_READ_URL";
|
|
280
288
|
};
|
|
@@ -284,6 +292,7 @@ declare const coreEnvSchema: {
|
|
|
284
292
|
examples: string[];
|
|
285
293
|
} & {
|
|
286
294
|
type: "string";
|
|
295
|
+
validator: (value: string) => string;
|
|
287
296
|
} & {
|
|
288
297
|
key: "CACHE_SENTINEL_HOSTS";
|
|
289
298
|
};
|
|
@@ -293,6 +302,7 @@ declare const coreEnvSchema: {
|
|
|
293
302
|
examples: string[];
|
|
294
303
|
} & {
|
|
295
304
|
type: "string";
|
|
305
|
+
validator: (value: string) => string;
|
|
296
306
|
} & {
|
|
297
307
|
key: "CACHE_CLUSTER_NODES";
|
|
298
308
|
};
|
|
@@ -302,6 +312,7 @@ declare const coreEnvSchema: {
|
|
|
302
312
|
examples: string[];
|
|
303
313
|
} & {
|
|
304
314
|
type: "string";
|
|
315
|
+
validator: (value: string) => string;
|
|
305
316
|
} & {
|
|
306
317
|
key: "CACHE_MASTER_NAME";
|
|
307
318
|
};
|
|
@@ -312,6 +323,7 @@ declare const coreEnvSchema: {
|
|
|
312
323
|
examples: string[];
|
|
313
324
|
} & {
|
|
314
325
|
type: "string";
|
|
326
|
+
validator: (value: string) => string;
|
|
315
327
|
} & {
|
|
316
328
|
key: "CACHE_PASSWORD";
|
|
317
329
|
};
|
|
@@ -342,6 +354,7 @@ declare const coreEnvSchema: {
|
|
|
342
354
|
examples: string[];
|
|
343
355
|
} & {
|
|
344
356
|
type: "string";
|
|
357
|
+
validator: (value: string) => string;
|
|
345
358
|
} & {
|
|
346
359
|
key: "HOST";
|
|
347
360
|
};
|
|
@@ -441,6 +454,7 @@ declare const registry: _spfn_core_env.EnvRegistry<{
|
|
|
441
454
|
examples: string[];
|
|
442
455
|
} & {
|
|
443
456
|
type: "string";
|
|
457
|
+
validator: (value: string) => string;
|
|
444
458
|
} & {
|
|
445
459
|
key: "DATABASE_URL";
|
|
446
460
|
};
|
|
@@ -452,6 +466,7 @@ declare const registry: _spfn_core_env.EnvRegistry<{
|
|
|
452
466
|
examples: string[];
|
|
453
467
|
} & {
|
|
454
468
|
type: "string";
|
|
469
|
+
validator: (value: string) => string;
|
|
455
470
|
} & {
|
|
456
471
|
key: "DATABASE_WRITE_URL";
|
|
457
472
|
};
|
|
@@ -463,6 +478,7 @@ declare const registry: _spfn_core_env.EnvRegistry<{
|
|
|
463
478
|
examples: string[];
|
|
464
479
|
} & {
|
|
465
480
|
type: "string";
|
|
481
|
+
validator: (value: string) => string;
|
|
466
482
|
} & {
|
|
467
483
|
key: "DATABASE_READ_URL";
|
|
468
484
|
};
|
|
@@ -633,6 +649,7 @@ declare const registry: _spfn_core_env.EnvRegistry<{
|
|
|
633
649
|
examples: string[];
|
|
634
650
|
} & {
|
|
635
651
|
type: "string";
|
|
652
|
+
validator: (value: string) => string;
|
|
636
653
|
} & {
|
|
637
654
|
key: "DRIZZLE_SCHEMA_PATH";
|
|
638
655
|
};
|
|
@@ -643,6 +660,7 @@ declare const registry: _spfn_core_env.EnvRegistry<{
|
|
|
643
660
|
examples: string[];
|
|
644
661
|
} & {
|
|
645
662
|
type: "string";
|
|
663
|
+
validator: (value: string) => string;
|
|
646
664
|
} & {
|
|
647
665
|
key: "DRIZZLE_OUT_DIR";
|
|
648
666
|
};
|
|
@@ -660,6 +678,7 @@ declare const registry: _spfn_core_env.EnvRegistry<{
|
|
|
660
678
|
examples: string[];
|
|
661
679
|
} & {
|
|
662
680
|
type: "string";
|
|
681
|
+
validator: (value: string) => string;
|
|
663
682
|
} & {
|
|
664
683
|
key: "CACHE_URL";
|
|
665
684
|
};
|
|
@@ -671,6 +690,7 @@ declare const registry: _spfn_core_env.EnvRegistry<{
|
|
|
671
690
|
examples: string[];
|
|
672
691
|
} & {
|
|
673
692
|
type: "string";
|
|
693
|
+
validator: (value: string) => string;
|
|
674
694
|
} & {
|
|
675
695
|
key: "CACHE_WRITE_URL";
|
|
676
696
|
};
|
|
@@ -682,6 +702,7 @@ declare const registry: _spfn_core_env.EnvRegistry<{
|
|
|
682
702
|
examples: string[];
|
|
683
703
|
} & {
|
|
684
704
|
type: "string";
|
|
705
|
+
validator: (value: string) => string;
|
|
685
706
|
} & {
|
|
686
707
|
key: "CACHE_READ_URL";
|
|
687
708
|
};
|
|
@@ -691,6 +712,7 @@ declare const registry: _spfn_core_env.EnvRegistry<{
|
|
|
691
712
|
examples: string[];
|
|
692
713
|
} & {
|
|
693
714
|
type: "string";
|
|
715
|
+
validator: (value: string) => string;
|
|
694
716
|
} & {
|
|
695
717
|
key: "CACHE_SENTINEL_HOSTS";
|
|
696
718
|
};
|
|
@@ -700,6 +722,7 @@ declare const registry: _spfn_core_env.EnvRegistry<{
|
|
|
700
722
|
examples: string[];
|
|
701
723
|
} & {
|
|
702
724
|
type: "string";
|
|
725
|
+
validator: (value: string) => string;
|
|
703
726
|
} & {
|
|
704
727
|
key: "CACHE_CLUSTER_NODES";
|
|
705
728
|
};
|
|
@@ -709,6 +732,7 @@ declare const registry: _spfn_core_env.EnvRegistry<{
|
|
|
709
732
|
examples: string[];
|
|
710
733
|
} & {
|
|
711
734
|
type: "string";
|
|
735
|
+
validator: (value: string) => string;
|
|
712
736
|
} & {
|
|
713
737
|
key: "CACHE_MASTER_NAME";
|
|
714
738
|
};
|
|
@@ -719,6 +743,7 @@ declare const registry: _spfn_core_env.EnvRegistry<{
|
|
|
719
743
|
examples: string[];
|
|
720
744
|
} & {
|
|
721
745
|
type: "string";
|
|
746
|
+
validator: (value: string) => string;
|
|
722
747
|
} & {
|
|
723
748
|
key: "CACHE_PASSWORD";
|
|
724
749
|
};
|
|
@@ -749,6 +774,7 @@ declare const registry: _spfn_core_env.EnvRegistry<{
|
|
|
749
774
|
examples: string[];
|
|
750
775
|
} & {
|
|
751
776
|
type: "string";
|
|
777
|
+
validator: (value: string) => string;
|
|
752
778
|
} & {
|
|
753
779
|
key: "HOST";
|
|
754
780
|
};
|
|
@@ -841,6 +867,7 @@ declare const env: _spfn_core_env.InferEnvType<{
|
|
|
841
867
|
examples: string[];
|
|
842
868
|
} & {
|
|
843
869
|
type: "string";
|
|
870
|
+
validator: (value: string) => string;
|
|
844
871
|
} & {
|
|
845
872
|
key: "DATABASE_URL";
|
|
846
873
|
};
|
|
@@ -852,6 +879,7 @@ declare const env: _spfn_core_env.InferEnvType<{
|
|
|
852
879
|
examples: string[];
|
|
853
880
|
} & {
|
|
854
881
|
type: "string";
|
|
882
|
+
validator: (value: string) => string;
|
|
855
883
|
} & {
|
|
856
884
|
key: "DATABASE_WRITE_URL";
|
|
857
885
|
};
|
|
@@ -863,6 +891,7 @@ declare const env: _spfn_core_env.InferEnvType<{
|
|
|
863
891
|
examples: string[];
|
|
864
892
|
} & {
|
|
865
893
|
type: "string";
|
|
894
|
+
validator: (value: string) => string;
|
|
866
895
|
} & {
|
|
867
896
|
key: "DATABASE_READ_URL";
|
|
868
897
|
};
|
|
@@ -1033,6 +1062,7 @@ declare const env: _spfn_core_env.InferEnvType<{
|
|
|
1033
1062
|
examples: string[];
|
|
1034
1063
|
} & {
|
|
1035
1064
|
type: "string";
|
|
1065
|
+
validator: (value: string) => string;
|
|
1036
1066
|
} & {
|
|
1037
1067
|
key: "DRIZZLE_SCHEMA_PATH";
|
|
1038
1068
|
};
|
|
@@ -1043,6 +1073,7 @@ declare const env: _spfn_core_env.InferEnvType<{
|
|
|
1043
1073
|
examples: string[];
|
|
1044
1074
|
} & {
|
|
1045
1075
|
type: "string";
|
|
1076
|
+
validator: (value: string) => string;
|
|
1046
1077
|
} & {
|
|
1047
1078
|
key: "DRIZZLE_OUT_DIR";
|
|
1048
1079
|
};
|
|
@@ -1060,6 +1091,7 @@ declare const env: _spfn_core_env.InferEnvType<{
|
|
|
1060
1091
|
examples: string[];
|
|
1061
1092
|
} & {
|
|
1062
1093
|
type: "string";
|
|
1094
|
+
validator: (value: string) => string;
|
|
1063
1095
|
} & {
|
|
1064
1096
|
key: "CACHE_URL";
|
|
1065
1097
|
};
|
|
@@ -1071,6 +1103,7 @@ declare const env: _spfn_core_env.InferEnvType<{
|
|
|
1071
1103
|
examples: string[];
|
|
1072
1104
|
} & {
|
|
1073
1105
|
type: "string";
|
|
1106
|
+
validator: (value: string) => string;
|
|
1074
1107
|
} & {
|
|
1075
1108
|
key: "CACHE_WRITE_URL";
|
|
1076
1109
|
};
|
|
@@ -1082,6 +1115,7 @@ declare const env: _spfn_core_env.InferEnvType<{
|
|
|
1082
1115
|
examples: string[];
|
|
1083
1116
|
} & {
|
|
1084
1117
|
type: "string";
|
|
1118
|
+
validator: (value: string) => string;
|
|
1085
1119
|
} & {
|
|
1086
1120
|
key: "CACHE_READ_URL";
|
|
1087
1121
|
};
|
|
@@ -1091,6 +1125,7 @@ declare const env: _spfn_core_env.InferEnvType<{
|
|
|
1091
1125
|
examples: string[];
|
|
1092
1126
|
} & {
|
|
1093
1127
|
type: "string";
|
|
1128
|
+
validator: (value: string) => string;
|
|
1094
1129
|
} & {
|
|
1095
1130
|
key: "CACHE_SENTINEL_HOSTS";
|
|
1096
1131
|
};
|
|
@@ -1100,6 +1135,7 @@ declare const env: _spfn_core_env.InferEnvType<{
|
|
|
1100
1135
|
examples: string[];
|
|
1101
1136
|
} & {
|
|
1102
1137
|
type: "string";
|
|
1138
|
+
validator: (value: string) => string;
|
|
1103
1139
|
} & {
|
|
1104
1140
|
key: "CACHE_CLUSTER_NODES";
|
|
1105
1141
|
};
|
|
@@ -1109,6 +1145,7 @@ declare const env: _spfn_core_env.InferEnvType<{
|
|
|
1109
1145
|
examples: string[];
|
|
1110
1146
|
} & {
|
|
1111
1147
|
type: "string";
|
|
1148
|
+
validator: (value: string) => string;
|
|
1112
1149
|
} & {
|
|
1113
1150
|
key: "CACHE_MASTER_NAME";
|
|
1114
1151
|
};
|
|
@@ -1119,6 +1156,7 @@ declare const env: _spfn_core_env.InferEnvType<{
|
|
|
1119
1156
|
examples: string[];
|
|
1120
1157
|
} & {
|
|
1121
1158
|
type: "string";
|
|
1159
|
+
validator: (value: string) => string;
|
|
1122
1160
|
} & {
|
|
1123
1161
|
key: "CACHE_PASSWORD";
|
|
1124
1162
|
};
|
|
@@ -1149,6 +1187,7 @@ declare const env: _spfn_core_env.InferEnvType<{
|
|
|
1149
1187
|
examples: string[];
|
|
1150
1188
|
} & {
|
|
1151
1189
|
type: "string";
|
|
1190
|
+
validator: (value: string) => string;
|
|
1152
1191
|
} & {
|
|
1153
1192
|
key: "HOST";
|
|
1154
1193
|
};
|
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);
|