Skip to content

Commit d405642

Browse files
ar27111994CopilotCopilot
authored
Fix processingTime semantics, schema caching, and restarts (#83)
* Fix processingTime semantics, schema caching, and restarts * fix(ci): stabilize link-check soft-fails * fix(pr): address review feedback and ci flake * fix(tests): clear follow-up lint and typing issues * fix(testing): harden teardown and document harness isolation * fix(runtime): harden latency metrics and restart-safe state * fix(runtime): reuse schema validators and harden duckdb resets * fix: drain server before sync and db shutdown * test: harden duckdb reset coverage guards * test: cover duckdb reset helpers deterministically * fix: prevent duckdb reset queue deadlock * test: remove unreachable duckdb branch * test: harden integration harness temp-dir setup * fix: Update src/db/duckdb.js stopWriteQueue() JSDoc Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix(docs): Update docs/architecture.md DuckDB reset process description to include updated reset behavior Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix: Update stopWriteQueue to drop waiting jobs during reset Co-authored-by: Copilot <copilot@github.com> * fix(db): invalidate late duckdb init after reset * fix(runtime): harden restart cleanup and worker settling * fix(ci): simplify test command in release workflow Co-authored-by: Copilot <copilot@github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Copilot <copilot@github.com>
1 parent c515b55 commit d405642

50 files changed

Lines changed: 3643 additions & 477 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.actor/actor.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"name": "webhook-debugger-logger",
44
"title": "Webhook Debugger, Logger & API Mocking Suite",
55
"description": "Enterprise-grade tool to test, debug, and mock webhooks. Features real-time SSE streaming, request replay, HTTP forwarding, and JSON schema validation. Perfect for Stripe, GitHub, and Shopify integrations.",
6-
"version": "3.0.4",
6+
"version": "3.0.5",
77
"output": "./output_schema.json",
88
"input": "./input_schema.json",
99
"webServerSchema": "./web_server_schema.json",

.actor/dataset_schema.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,8 @@
104104
},
105105
"processingTime": {
106106
"type": "integer",
107-
"title": "Latency (ms)",
108-
"description": "Time taken to process the request",
107+
"title": "Processing Time (ms)",
108+
"description": "Time taken to process the request before any simulated response delay is applied",
109109
"example": 5
110110
},
111111
"remoteIp": {
@@ -224,7 +224,7 @@
224224
"label": "Size (Bytes)"
225225
},
226226
"processingTime": {
227-
"label": "Latency (ms)"
227+
"label": "Processing Time (ms)"
228228
},
229229
"remoteIp": {
230230
"label": "Source IP"

.actor/output_schema.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,13 @@
3838
"desc": true
3939
},
4040
"display": {
41-
"component": "table"
41+
"component": "table",
42+
"properties": {
43+
"processingTime": {
44+
"label": "Processing Time (ms)",
45+
"format": "number"
46+
}
47+
}
4248
}
4349
},
4450
"details": {

.actor/web_server_schema.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"info": {
44
"title": "Webhook Debugger & Logger API",
55
"description": "OpenAPI description for the Webhook Debugger & Logger Actor web server. Authentication is configuration-driven: when authKey is configured, management routes require either a bearer token or the key query parameter; when authKey is unset, those routes remain accessible without credentials.",
6-
"version": "3.0.4"
6+
"version": "3.0.5"
77
},
88
"servers": [
99
{
@@ -80,7 +80,7 @@
8080
"schema": {
8181
"type": "string"
8282
},
83-
"example": "Webhook Debugger & Logger (v3.0.4)\nActive Webhooks: 1\nSignature Verification: STRIPE"
83+
"example": "Webhook Debugger & Logger (v3.0.5)\nActive Webhooks: 1\nSignature Verification: STRIPE"
8484
}
8585
}
8686
},
@@ -1137,7 +1137,8 @@
11371137
"type": "integer"
11381138
},
11391139
"processingTime": {
1140-
"type": "integer"
1140+
"type": "integer",
1141+
"description": "Server-side processing time in milliseconds before any configured responseDelayMs simulation is applied"
11411142
},
11421143
"requestId": {
11431144
"type": "string"

.claude/rules/testing.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,13 @@ const wait = (ms) => new Promise((r) => setTimeout(r, ms));
5454
### shared-mocks.js
5555

5656
- `apifyMock`, `axiosMock`, `dnsPromisesMock`, `ssrfMock` - Pre-configured mocks
57+
- `apifyMock` includes both `Actor.on(...)` and `Actor.off(...)` support for lifecycle-oriented harness teardown
5758
- `createDatasetMock(items, { autoRegister })` - Dataset with getData/pushData/getInfo
5859
- `createKeyValueStoreMock(overrides)` - KV store mock
5960
- `createMockWebhookManager(overrides)` - WebhookManager mock
6061
- `setupBasicApifyMock(mockInstance, options)` - Configure apifyMock
6162
- `resetNetworkMocks()` - Reset SSRF, DNS, Axios to defaults
63+
- `fsPromisesMock` - Shared `node:fs/promises` mock surface, including `mkdtemp()` for temp-dir based harness setup
6264
- `loggerMock` - Shared logger mock for assertions
6365

6466
### test-utils.js
@@ -77,7 +79,7 @@ const wait = (ms) => new Promise((r) => setTimeout(r, ms));
7779
### Other Helpers
7880

7981
- `middleware-test-utils.js`: `createMiddlewareTestContext()`, `runMiddlewareWithTimers()`
80-
- `app-utils.js`: `setupTestApp()` - Initialize app + supertest for integration tests
82+
- `app-utils.js`: `setupTestApp()` - Initialize app + supertest for integration tests; teardown also removes transient Actor listeners and process signal handlers registered during boot. Suites that use it must keep `mkdtemp()` real or provide a real mock implementation.
8183
- `db-hooks.js`: `resetDb()` - Clear DuckDB logs table
8284
- `signature-utils.js`: `createStripeSignature()`, `createShopifySignature()`, `createGitHubSignature()`, `createSlackSignature()`
8385

@@ -231,13 +233,19 @@ let appClient, teardownApp;
231233
beforeAll(async () => {
232234
({ appClient, teardownApp } = await setupTestApp());
233235
});
234-
afterAll(() => teardownApp());
236+
afterAll(async () => {
237+
await teardownApp();
238+
});
235239

236240
test("GET /health", async () => {
237241
expect((await appClient.get("/health")).status).toBe(200);
238242
});
239243
```
240244

245+
Use the harness teardown instead of manually removing process or Actor listeners inside individual integration suites.
246+
247+
Do not enable `setupCommonMocks({ fs: true })` in suites that call `setupTestApp()` or `startIntegrationApp()` unless you explicitly wire `fsPromisesMock.mkdtemp` to a real temp-directory implementation. The harness relies on a unique `APIFY_LOCAL_STORAGE_DIR` per boot and now throws if `mkdtemp()` returns an empty or invalid path.
248+
241249
### Dataset Mocking
242250

243251
```javascript

.github/workflows/link-check.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,11 @@ jobs:
103103
104104
try {
105105
const { origin, pathname } = new URL(value);
106-
return `${origin}${pathname}`;
106+
const normalizedPathname =
107+
pathname !== '/' && pathname.endsWith('/')
108+
? pathname.slice(0, -1)
109+
: pathname;
110+
return `${origin}${normalizedPathname}`;
107111
} catch {
108112
return null;
109113
}
@@ -114,6 +118,9 @@ jobs:
114118
'https://www.npmjs.com/package/webhook-debugger-logger',
115119
'https://www.npmjs.com/package/isolated-vm?activeTab=readme',
116120
'https://img.shields.io/coderabbit/prs/github/ar27111994/webhook-debugger-logger?utm_source=oss&utm_medium=github&utm_campaign=ar27111994%2Fwebhook-debugger-logger&labelColor=171717&color=FF570A&link=https%3A%2F%2Fcoderabbit.ai&label=CodeRabbit+Reviews',
121+
'https://www.patreon.com/cw/ar27111994',
122+
'https://liberapay.com/ar27111994',
123+
'https://thanks.dev/d/gh/ar27111994',
117124
];
118125
const softHandledUrlKeys = new Set(
119126
softHandledUrls.map((value) => normalizeUrlKey(value)).filter(Boolean),

.github/workflows/release-npm.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
run: npm run validate:schemas
2929

3030
- name: Verify Builds/Tests
31-
run: npm run test:jest -- --detectOpenHandles --forceExit
31+
run: npm test
3232

3333
- name: Confirm publish is deferred outside release events
3434
if: github.event_name != 'release'

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ coverage/
1212
!.github/coverage/
1313
!.github/coverage/*.json
1414
.tsbuildinfo
15+
*.tmp*

.lycheeignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@
2626
^(?:http://)169\.254\.169\.254/latest(?:/|$)
2727
^(?:http://)(?:empty\.domain|nonexistent\.domain)(?:/|$)
2828
^(?:http://)(?:weird-dns|string-throw)\.com(?:/|$)
29+
^(?:http://)metadata\.cloud(?:/|$)
2930
^(?:https://)xn--unicode-domain\.com(?:/|$)
3031
^(?:https://)google\.com/foo(?:/|$)

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,25 @@
33
All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
55

6+
## [3.0.5] - 2026-04-21
7+
8+
### Fixed (3.0.5)
9+
10+
- **Latency Metrics**: Make `processingTime` consistently represent server-side processing time only, excluding any configured `responseDelayMs` simulation from persisted log data.
11+
- **Performance**: Cache compiled JSON Schema validators so repeated requests and stable hot-reload configurations do not trigger unnecessary recompilation on the webhook path.
12+
- **Lifecycle**: Reset webhook-manager singleton state during test teardown and recreate the sync-service limiter after shutdown so repeated initialize/stop/start flows remain stable.
13+
- **Lifecycle**: Cache the active `SyncService` limiter stop promise so disconnect cleanup can be retried safely after a partial stop failure, and so a later `start()` drains stale limiter cleanup before creating a replacement scheduler.
14+
- **Shutdown Ordering**: Drain the HTTP listener before stopping `SyncService` and closing DuckDB so in-flight requests and readiness probes do not race read-model teardown.
15+
- **DuckDB Lifecycle**: Drain both pooled and in-use DuckDB connections before resetting the singleton so repeated DB teardown and rebuild flows do not leave stale handles behind.
16+
- **DuckDB Reset Coordination**: Keep the reset gate for new DuckDB callers while allowing already-queued writes and transactions to drain first, preventing reset deadlocks in the serialized write path.
17+
- **DuckDB Init Invalidation**: Prevent an in-flight DuckDB initializer from republishing a stale singleton after `resetDbInstance()` clears teardown state, and allow clean reinitialization even when that late initializer ultimately fails.
18+
- **Contracts & Docs**: Align dataset, output, OpenAPI, README, architecture, and API reference documentation with the finalized `processingTime` semantics and response-delay behavior.
19+
- **Worker Cleanup**: Remove the custom script executor's `void` cleanup chaining and keep message/error/exit settlement deterministic even when worker listener cleanup throws.
20+
- **Tests**: Add regression coverage for latency semantics, validator-cache reuse and memoized schema cache keys, DuckDB reset coordination with active reads plus queued write/transaction drain paths, malformed JSON sanitation persistence, restart-safe integration harness cleanup, shutdown-only sync error suppression, and spawned-process close-path resilience.
21+
- **Tests**: Add focused regression coverage for `SyncService` stop/start retry paths and custom-script worker cleanup failure handling, and drive the touched files to 100% focused unit coverage before rerunning the stress suite.
22+
- **Tests**: Make `setupTestApp()` fail fast when `node:fs/promises.mkdtemp()` is mocked incorrectly, and keep in-process integration suites on a real temp-directory implementation so `APIFY_LOCAL_STORAGE_DIR` isolation stays intact.
23+
- **Tooling**: Remove the unused `cross-env` dependency and keep `npm run test:stress` on a direct Node + Jest invocation with `--expose-gc`, which works after a native Windows dependency install regenerates the local toolchain.
24+
625
## [3.0.4] - 2026-04-18
726

827
### Fixed (3.0.4)

0 commit comments

Comments
 (0)