Merge pull request #75 from PR0M3TH3AN/perf/torch-timeout-fix-10089523949735471707

perf(torch): fix 15s delay in lock queries by clearing timeout
This commit is contained in:
thePR0M3TH3AN authored and GitHub committed 2026-02-14 09:28:57 -05:00
commit 4c15736b99
5 files changed
+78 -3

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
Benchmarking "node bin/torch-lock.mjs list" (5 iterations)...
Run 1: 5233.54ms
Run 2: 928.75ms
Run 3: 949.99ms
Run 4: 974.20ms
Run 5: 5214.18ms
Results:
Count: 5
Average: 2660.13ms
Min: 928.75ms
Max: 5233.54ms
+12
View File
@@ -0,0 +1,12 @@
Benchmarking "node bin/torch-lock.mjs list" (5 iterations)...
Run 1: 15259.19ms
Run 2: 15255.13ms
Run 3: 15210.17ms
Run 4: 15190.69ms
Run 5: 15182.21ms
Results:
Count: 5
Average: 15219.48ms
Min: 15182.21ms
Max: 15259.19ms
+24
View File
@@ -0,0 +1,24 @@
# Diagnosis: 15s Execution Floor in Lock Queries
## Observation
The command `torch-lock list` and other lock operations consistently take slightly over 15 seconds to complete, even when network conditions are good and relays respond quickly (within <1s).
## Root Cause Analysis
The `queryLocks` function in `src/lock-ops.mjs` uses `Promise.race` to enforce a timeout (default 15s) on relay queries.
```javascript
const events = await Promise.race([
pool.querySync(relays, { ... }),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Relay query timed out')), queryTimeoutMs),
),
]);
```
When `pool.querySync` completes successfully (e.g., in 600ms), the `Promise.race` resolves immediately. However, the `setTimeout` created in the second promise remains active in the Node.js event loop. Node.js processes do not exit as long as there are active handles (like timers). Thus, the process waits for the remaining ~14.4s until the timer fires (and the callback is executed, though ignored) before exiting.
## Verification
A reproduction script confirmed that `Promise.race` with an uncleared `setTimeout` prevents process exit until the timeout fires.
## Proposed Fix
Capture the `timeoutHandle` from `setTimeout` and explicitly clear it using `clearTimeout(timeoutHandle)` in the `finally` block of the `queryLocks` function.
+8 -3
View File
@@ -46,19 +46,24 @@ export async function queryLocks(relays, cadence, dateStr, namespace) {
const tagFilter = `${namespace}-lock-${cadence}-${dateStr}`;
const queryTimeoutMs = getQueryTimeoutMs();
let timeoutHandle;
try {
const events = await Promise.race([
pool.querySync(relays, {
kinds: [30078],
'#t': [tagFilter],
}),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Relay query timed out')), queryTimeoutMs),
),
new Promise((_, reject) => {
timeoutHandle = setTimeout(() => reject(new Error('Relay query timed out')), queryTimeoutMs);
}),
]);
return filterActiveLocks(events.map(parseLockEvent));
} finally {
if (timeoutHandle) {
clearTimeout(timeoutHandle);
}
pool.close(relays);
}
}
@@ -0,0 +1,22 @@
# Task Log: perf-optimization-agent
**Status:** Completed
**Date:** 2026-02-14
**Agent:** perf-optimization-agent
## Diagnosis
Identified a 15-second execution floor in `torch-lock` operations caused by a `Promise.race` timeout that was not cleared upon successful completion. This kept the Node.js event loop active until the 15s timer fired.
## Action Taken
Modified `src/lock-ops.mjs` to capture the timeout handle and explicitly clear it using `clearTimeout` in the `finally` block of `queryLocks`.
## Verification
- **Baseline:** ~15.2s average execution time.
- **After:** ~2.6s average execution time (min ~0.9s).
- **Tests:** `npm test` passed successfully.
- **Lint:** `npm run lint` passed.
## Artifacts
- `DIAGNOSIS.md`
- `BASELINE.md`
- `AFTER.md`