tradeblocks-mcp 3.10.1 → 3.10.2
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/{chunk-JTNPDIFG.js → chunk-TZRDK5VL.js} +100 -13
- package/dist/chunk-TZRDK5VL.js.map +1 -0
- package/dist/{sync-7O6U2M2G.js → sync-DVSXIIUZ.js} +2 -2
- package/dist/test-exports.js +34 -1
- package/dist/test-exports.js.map +1 -1
- package/package.json +1 -1
- package/server/{chunk-P53XQSWI.js → chunk-GKB4EQFU.js} +94 -13
- package/server/chunk-GKB4EQFU.js.map +1 -0
- package/server/index.js +32 -6
- package/server/index.js.map +1 -1
- package/server/{sync-B7JR7UQF.js → sync-MW333YEK.js} +2 -2
- package/src/db/connection.ts +225 -21
- package/src/db/index.ts +4 -0
- package/src/index.ts +7 -2
- package/src/test-exports.ts +5 -0
- package/src/tools/middleware/connection-lease.ts +73 -0
- package/dist/chunk-JTNPDIFG.js.map +0 -1
- package/server/chunk-P53XQSWI.js.map +0 -1
- /package/dist/{sync-7O6U2M2G.js.map → sync-DVSXIIUZ.js.map} +0 -0
- /package/server/{sync-B7JR7UQF.js.map → sync-MW333YEK.js.map} +0 -0
|
@@ -3435,6 +3435,10 @@ async function migrateMetadataToJson(conn, dataDir, blocksDir) {
|
|
|
3435
3435
|
}
|
|
3436
3436
|
|
|
3437
3437
|
// src/db/connection.ts
|
|
3438
|
+
var leaseCount = 0;
|
|
3439
|
+
var idleTimer = null;
|
|
3440
|
+
var openInFlight = null;
|
|
3441
|
+
var closeInFlight = null;
|
|
3438
3442
|
var instance = null;
|
|
3439
3443
|
var connection = null;
|
|
3440
3444
|
var connectionMode = null;
|
|
@@ -3631,7 +3635,7 @@ async function openReadWriteConnection(dbPath, threads, memoryLimit) {
|
|
|
3631
3635
|
await createMarketParquetViews(connection, dataRoot);
|
|
3632
3636
|
await ensureMarketDataTables(connection);
|
|
3633
3637
|
try {
|
|
3634
|
-
const blocksDir = (await import("./sync-
|
|
3638
|
+
const blocksDir = (await import("./sync-DVSXIIUZ.js")).getBlocksDir(dataRoot);
|
|
3635
3639
|
await migrateMetadataToJson(connection, dataRoot, blocksDir);
|
|
3636
3640
|
} catch (err) {
|
|
3637
3641
|
console.warn(
|
|
@@ -3657,6 +3661,7 @@ async function openReadOnlyConnection(dbPath, threads, memoryLimit) {
|
|
|
3657
3661
|
return connection;
|
|
3658
3662
|
}
|
|
3659
3663
|
function resetConnectionState() {
|
|
3664
|
+
cancelIdleRelease();
|
|
3660
3665
|
if (connection) {
|
|
3661
3666
|
try {
|
|
3662
3667
|
connection.closeSync();
|
|
@@ -3674,9 +3679,24 @@ function resetConnectionState() {
|
|
|
3674
3679
|
connectionMode = null;
|
|
3675
3680
|
}
|
|
3676
3681
|
async function getConnection(dataDir) {
|
|
3682
|
+
if (closeInFlight) {
|
|
3683
|
+
await closeInFlight;
|
|
3684
|
+
}
|
|
3677
3685
|
if (connection) {
|
|
3678
3686
|
return connection;
|
|
3679
3687
|
}
|
|
3688
|
+
if (openInFlight) {
|
|
3689
|
+
return openInFlight;
|
|
3690
|
+
}
|
|
3691
|
+
openInFlight = openConnectionUnshared(dataDir).then((conn) => {
|
|
3692
|
+
if (leaseCount === 0) scheduleIdleRelease();
|
|
3693
|
+
return conn;
|
|
3694
|
+
}).finally(() => {
|
|
3695
|
+
openInFlight = null;
|
|
3696
|
+
});
|
|
3697
|
+
return openInFlight;
|
|
3698
|
+
}
|
|
3699
|
+
async function openConnectionUnshared(dataDir) {
|
|
3680
3700
|
const dbPath = path11.join(dataDir, "analytics.duckdb");
|
|
3681
3701
|
const threads = process.env.DUCKDB_THREADS || defaultThreads();
|
|
3682
3702
|
const memoryLimit = process.env.DUCKDB_MEMORY_LIMIT || defaultMemoryLimit();
|
|
@@ -3728,14 +3748,14 @@ async function openWithLockContention(dbPath, dataDir, threads, memoryLimit, for
|
|
|
3728
3748
|
if (!isLockError(roMessage)) throw roError;
|
|
3729
3749
|
resetConnectionState();
|
|
3730
3750
|
}
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3751
|
+
if (terminations < MAX_TERMINATIONS) {
|
|
3752
|
+
const terminated = await tryRecoverLockByTerminatingStaleProcess(
|
|
3753
|
+
lastLockError,
|
|
3754
|
+
dbPath,
|
|
3755
|
+
forceRecovery
|
|
3756
|
+
);
|
|
3757
|
+
if (terminated) {
|
|
3758
|
+
terminations += 1;
|
|
3739
3759
|
attempt = 0;
|
|
3740
3760
|
continue;
|
|
3741
3761
|
}
|
|
@@ -3754,12 +3774,74 @@ async function openWithLockContention(dbPath, dataDir, threads, memoryLimit, for
|
|
|
3754
3774
|
await new Promise((r) => setTimeout(r, Math.min(delayMs, Math.max(0, deadline - Date.now()))));
|
|
3755
3775
|
}
|
|
3756
3776
|
}
|
|
3757
|
-
|
|
3777
|
+
var DEFAULT_IDLE_RELEASE_MS = 3e3;
|
|
3778
|
+
function idleReleaseMs() {
|
|
3779
|
+
const raw = Number.parseInt(process.env.DUCKDB_IDLE_RELEASE_MS || "", 10);
|
|
3780
|
+
return Number.isFinite(raw) && raw >= 0 ? raw : DEFAULT_IDLE_RELEASE_MS;
|
|
3781
|
+
}
|
|
3782
|
+
function cancelIdleRelease() {
|
|
3783
|
+
if (idleTimer) {
|
|
3784
|
+
clearTimeout(idleTimer);
|
|
3785
|
+
idleTimer = null;
|
|
3786
|
+
}
|
|
3787
|
+
}
|
|
3788
|
+
function scheduleIdleRelease() {
|
|
3789
|
+
cancelIdleRelease();
|
|
3790
|
+
if (leaseCount > 0) return;
|
|
3791
|
+
const delay = idleReleaseMs();
|
|
3792
|
+
idleTimer = setTimeout(() => {
|
|
3793
|
+
idleTimer = null;
|
|
3794
|
+
if (leaseCount > 0) return;
|
|
3795
|
+
closeConnection({ abortIfLeased: true }).catch((error) => {
|
|
3796
|
+
console.error(
|
|
3797
|
+
`Failed to release the idle DuckDB handle: ${error instanceof Error ? error.message : String(error)}`
|
|
3798
|
+
);
|
|
3799
|
+
});
|
|
3800
|
+
}, delay);
|
|
3801
|
+
idleTimer.unref?.();
|
|
3802
|
+
}
|
|
3803
|
+
function acquireConnectionLease() {
|
|
3804
|
+
leaseCount += 1;
|
|
3805
|
+
cancelIdleRelease();
|
|
3806
|
+
}
|
|
3807
|
+
function releaseConnectionLease() {
|
|
3808
|
+
if (leaseCount === 0) return;
|
|
3809
|
+
leaseCount -= 1;
|
|
3810
|
+
if (leaseCount === 0) {
|
|
3811
|
+
scheduleIdleRelease();
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
function getConnectionLeaseCount() {
|
|
3815
|
+
return leaseCount;
|
|
3816
|
+
}
|
|
3817
|
+
async function withConnectionLease(work) {
|
|
3818
|
+
acquireConnectionLease();
|
|
3819
|
+
try {
|
|
3820
|
+
return await work();
|
|
3821
|
+
} finally {
|
|
3822
|
+
releaseConnectionLease();
|
|
3823
|
+
}
|
|
3824
|
+
}
|
|
3825
|
+
async function closeConnection(options) {
|
|
3826
|
+
if (closeInFlight) {
|
|
3827
|
+
return closeInFlight;
|
|
3828
|
+
}
|
|
3829
|
+
closeInFlight = closeConnectionUnshared(options).finally(() => {
|
|
3830
|
+
closeInFlight = null;
|
|
3831
|
+
});
|
|
3832
|
+
return closeInFlight;
|
|
3833
|
+
}
|
|
3834
|
+
async function closeConnectionUnshared(options) {
|
|
3835
|
+
const abortIfLeased = options?.abortIfLeased === true;
|
|
3836
|
+
cancelIdleRelease();
|
|
3758
3837
|
if (connection) {
|
|
3759
3838
|
try {
|
|
3760
3839
|
await connection.run("CHECKPOINT");
|
|
3761
3840
|
} catch {
|
|
3762
3841
|
}
|
|
3842
|
+
if (abortIfLeased && leaseCount > 0) {
|
|
3843
|
+
return;
|
|
3844
|
+
}
|
|
3763
3845
|
try {
|
|
3764
3846
|
await detachMarketDb(connection);
|
|
3765
3847
|
} catch {
|
|
@@ -3790,7 +3872,8 @@ async function upgradeToReadWrite(dataDir, options) {
|
|
|
3790
3872
|
if (!storedMarketDbPath) {
|
|
3791
3873
|
storedMarketDbPath = resolveMarketDbPath(dataDir);
|
|
3792
3874
|
}
|
|
3793
|
-
const
|
|
3875
|
+
const configuredRetries = Number.parseInt(process.env.DUCKDB_WRITE_LOCK_RETRIES || "", 10);
|
|
3876
|
+
const maxRetries = Number.isFinite(configuredRetries) && configuredRetries >= 0 ? configuredRetries : 10;
|
|
3794
3877
|
const retryDelayMs = 1e3;
|
|
3795
3878
|
let lastError = null;
|
|
3796
3879
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
@@ -3949,7 +4032,7 @@ function isConnected() {
|
|
|
3949
4032
|
function getCurrentConnection() {
|
|
3950
4033
|
if (!connection) {
|
|
3951
4034
|
throw new Error(
|
|
3952
|
-
"No active DuckDB connection.
|
|
4035
|
+
"No active DuckDB connection. The handle is released when idle (#445), so a store context must only be used inside a leased unit of work \u2014 the tool wrapper in index.ts takes that lease for every registered tool. Code reaching here runs outside any lease: wrap it in withConnectionLease()."
|
|
3953
4036
|
);
|
|
3954
4037
|
}
|
|
3955
4038
|
return connection;
|
|
@@ -5521,6 +5604,10 @@ export {
|
|
|
5521
5604
|
createMarketParquetViews,
|
|
5522
5605
|
migrateMetadataToJson,
|
|
5523
5606
|
getConnection,
|
|
5607
|
+
acquireConnectionLease,
|
|
5608
|
+
releaseConnectionLease,
|
|
5609
|
+
getConnectionLeaseCount,
|
|
5610
|
+
withConnectionLease,
|
|
5524
5611
|
closeConnection,
|
|
5525
5612
|
upgradeToReadWrite,
|
|
5526
5613
|
downgradeToReadOnly,
|
|
@@ -5536,4 +5623,4 @@ export {
|
|
|
5536
5623
|
loadReportingLog,
|
|
5537
5624
|
importCsv
|
|
5538
5625
|
};
|
|
5539
|
-
//# sourceMappingURL=chunk-
|
|
5626
|
+
//# sourceMappingURL=chunk-TZRDK5VL.js.map
|