Webhook Isolation & Metering
Overview
Webhook-triggered workflows run headless. To protect availability and enable billing/analytics, each invocation executes in an isolated environment with strict time/memory limits and emits per-node metering events.
Isolation Strategy (Vercel)
- Route Handler runtime: Node.js (
export const runtime = 'nodejs'
) withexport const maxDuration
tuned per plan - Per-request isolation:
worker_threads
Worker for the entire workflow run - Resource limits: set Worker
resourceLimits
(heap caps) and watchdog timer; terminate on timeout - Safe code execution: continue to use
executeInSandbox
for Code nodes, but rely on Worker for preemption if user code blocks the event loop - Long-running jobs: return 202 +
runId
and process in a Background Function/Queue consumer
Metering Hooks
- Extend
WorkflowExecutorCore
withonMeter(event)
- Emit on:
- Node start/complete/error: duration, outcome
- AI calls: model, prompt/completion/total tokens
- HTTP: requests count and bytes in/out per node
- Plugin: invocations per plugin ID
- Timeouts/terminations
Data Flow
Request → Route Handler → start Worker
↘︎ meter events (postMessage)
Worker → load workflow/context → execute core → emit meter events
→ post final result → terminate
Example (sketch)
// api/webhooks/[id]/route.ts
export const runtime = 'nodejs'
export const maxDuration = 300
import { Worker } from 'node:worker_threads'
export async function POST(req, { params }) {
const payload = {/* webhook + user context */}
const worker = new Worker('src/lib/executors/webhook-worker.js', {
resourceLimits: { maxOldGenerationSizeMb: 128 }
})
const result = await new Promise((resolve, reject) => {
const timer = setTimeout(() => { worker.terminate(); reject(new Error('timeout')) }, 280000)
worker.once('message', (msg) => { clearTimeout(timer); resolve(msg) })
worker.once('error', (err) => { clearTimeout(timer); reject(err) })
worker.postMessage(payload)
})
return NextResponse.json(result)
}
In the worker, pass onMeter
to WorkflowExecutorCore
and parentPort.postMessage
/enqueue to persist.
Security
- No secrets in meter payloads
- Validate webhook auth (API key, Bearer, Basic, HMAC)
- Enforce per-user quotas before execution; short-circuit if exceeded
Operational Notes
- Batch writes for meter events
- Backpressure: drop non-critical dimensions first
- Observability: log terminations/timeouts with runId