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.
@@ -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-7O6U2M2G.js")).getBlocksDir(dataRoot);
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
- const terminated = await tryRecoverLockByTerminatingStaleProcess(
3732
- lastLockError,
3733
- dbPath,
3734
- forceRecovery
3735
- );
3736
- if (terminated) {
3737
- terminations += 1;
3738
- if (terminations <= MAX_TERMINATIONS) {
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
- async function closeConnection() {
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 maxRetries = 4;
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. Call getConnection(dataDir) during server init before accessing store contexts."
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-JTNPDIFG.js.map
5626
+ //# sourceMappingURL=chunk-TZRDK5VL.js.map