Skip to content

Comments

fix(mongodb): prevent webhook response stream close race#33

Merged
dustintownsend merged 1 commit intomainfrom
codex/fix-mongodb-webhook-race
Feb 9, 2026
Merged

fix(mongodb): prevent webhook response stream close race#33
dustintownsend merged 1 commit intomainfrom
codex/fix-mongodb-webhook-race

Conversation

@dustintownsend
Copy link
Contributor

Summary

  • fix a race in MongoDB streamer readFromStream() where a close signal could arrive during initial load and close the reader before buffered chunks were delivered
  • defer close until initial-load buffered chunks are flushed
  • guard against duplicate/late close handling with explicit closed state
  • add a regression test that repeatedly exercises read-before-write with immediate close (the webhook response pattern)

Why

The MongoDB E2E webhookWorkflow failure (expected '' to be 'Hello from webhook!') is consistent with a dropped stream chunk when close and first chunk occur back-to-back.

Validation

  • pnpm --filter @workflow-worlds/mongodb test:only
    • result: 55 passed, 0 failed

@github-actions
Copy link
Contributor

github-actions bot commented Feb 9, 2026

Benchmark Comparison

Cross-comparison of workflow performance across World implementations.

📈 Comparing against baseline from main branch. Green 🟢 = faster, Red 🔺 = slower.

workflow with no steps

World Workflow Time Wall Time Overhead vs Fastest
🥇 💾 Starter (in-memory) 0.008s (-43.4% 🟢) 1.006s (~) 0.997s 1.00x
🔴 Redis 0.020s (~) 1.010s (~) 0.990s 2.51x
💻 Local 0.028s (+0.7%) 1.007s (~) 0.979s 3.40x
🍃 MongoDB 0.049s (+5.0%) 1.010s (~) 0.961s 5.99x
🗄️ Turso 0.092s (+152.5% 🔺) 1.010s (~) 0.917s 11.41x

workflow with 1 step

World Workflow Time Wall Time Overhead vs Fastest
🥇 💾 Starter (in-memory) 0.023s (-44.0% 🟢) 1.004s (~) 0.980s 1.00x
🔴 Redis 0.057s (+2.9%) 1.007s (~) 0.949s 2.44x
💻 Local 0.080s (-17.3% 🟢) 1.006s (~) 0.925s 3.43x
🍃 MongoDB 0.253s (-8.5% 🟢) 1.009s (~) 0.756s 10.82x
🗄️ Turso 0.294s (+21.4% 🔺) 1.008s (-1.4%) 0.714s 12.57x

workflow with 10 sequential steps

World Workflow Time Wall Time Overhead vs Fastest
🥇 💾 Starter (in-memory) 0.199s (-40.6% 🟢) 1.003s (~) 0.804s 1.00x
🔴 Redis 0.422s (~) 1.006s (~) 0.584s 2.12x
💻 Local 0.640s (-1.4%) 1.005s (~) 0.365s 3.21x
🍃 MongoDB 2.102s (-1.4%) 3.011s (~) 0.909s 10.55x
🗄️ Turso 2.111s (~) 3.008s (~) 0.897s 10.60x

workflow with 10 parallel steps

World Workflow Time Wall Time Overhead vs Fastest
🥇 💾 Starter (in-memory) 0.094s (-27.3% 🟢) 1.004s (~) 0.910s 1.00x
🔴 Redis 0.162s (-0.6%) 1.006s (~) 0.844s 1.71x
💻 Local 0.273s (-1.5%) 1.006s (~) 0.732s 2.89x
🗄️ Turso 1.525s (-3.2%) 2.008s (~) 0.483s 16.16x
🍃 MongoDB 1.570s (~) 2.009s (~) 0.439s 16.63x

Stream Benchmarks

Stream benchmarks include Time to First Byte (TTFB) metrics.

workflow with stream

World Workflow Time TTFB Wall Time Overhead vs Fastest
🥇 💾 Starter (in-memory) 0.037s (-47.3% 🟢) 1.003s (~) 1.005s (~) 0.968s 1.00x
🔴 Redis 0.090s (~) 1.002s (~) 1.007s (~) 0.917s 2.40x
💻 Local 0.137s (-1.9%) 0.992s (~) 1.008s (~) 0.871s 3.65x
🗄️ Turso 0.472s (+6.0% 🔺) 0.960s (-2.6%) 1.008s (~) 0.537s 12.58x
🍃 MongoDB 0.480s (-3.2%) 0.951s (+1.7%) 1.009s (~) 0.528s 12.81x

Summary: Average Performance by World

World Avg Workflow Time Benchmarks
💾 Starter (in-memory) 0.073s 5
🔴 Redis 0.150s 5
💻 Local 0.232s 5
🍃 MongoDB 0.891s 5
🗄️ Turso 0.899s 5
Column Definitions
  • Workflow Time: Runtime reported by workflow (completedAt - createdAt) - primary metric
  • TTFB: Time to First Byte - time from workflow start until first stream byte received (stream benchmarks only)
  • Wall Time: Total testbench time (trigger workflow + poll for result)
  • Overhead: Testbench overhead (Wall Time - Workflow Time)
  • vs Fastest: How much slower compared to the fastest World for this benchmark

Worlds:

  • 💻 Local: Built-in workflow world
  • 🐘 Postgres: PostgreSQL database world
  • ▲ Vercel: Vercel production world
  • 💾 Starter: In-memory reference implementation
  • 🍃 MongoDB: MongoDB database world
  • 🔴 Redis: Redis/BullMQ backend

@github-actions
Copy link
Contributor

github-actions bot commented Feb 9, 2026

❌ E2E Test Results

World Passed Failed Skipped Total
Turso 26 19 3 48
MongoDB 45 0 3 48
Redis 45 0 3 48
Total 116 19 9 144

Failed Tests

Turso — 19 failed
  • e2e concurrent hook token conflict - two workflows cannot use the same hook token simultaneously

    LibsqlError: SQLITE_BUSY: database is locked

  • e2e stepFunctionPassingWorkflow - step function references can be passed as arguments (without closure vars)

    Error: STACK_TRACE_ERROR

  • e2e stepFunctionWithClosureWorkflow - step function with closure variables passed as argument

    Error: STACK_TRACE_ERROR

  • e2e closureVariableWorkflow - nested step functions with closure variables

    Error: STACK_TRACE_ERROR

  • e2e spawnWorkflowFromStepWorkflow - spawning a child workflow using start() inside a step

    Error: STACK_TRACE_ERROR

  • e2e health check (queue-based) - workflow and step endpoints respond to health check messages

    AssertionError: expected false to be true // Object.is equality

  • e2e health check (CLI) - workflow health command reports healthy endpoints

    AssertionError: expected false to be true // Object.is equality

  • e2e pathsAliasWorkflow - TypeScript path aliases resolve correctly

    Error: STACK_TRACE_ERROR

  • e2e Calculator.calculate - static workflow method using static step methods from another class

    Error: STACK_TRACE_ERROR

  • e2e AllInOneService.processNumber - static workflow method using sibling static step methods

    Error: STACK_TRACE_ERROR

  • e2e ChainableService.processWithThis - static step methods using this to reference the class

    Error: STACK_TRACE_ERROR

  • e2e thisSerializationWorkflow - step function invoked with .call() and .apply()

    Error: STACK_TRACE_ERROR

  • e2e customSerializationWorkflow - custom class serialization with WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE

    Error: STACK_TRACE_ERROR

  • e2e instanceMethodStepWorkflow - instance methods with "use step" directive

    Error: STACK_TRACE_ERROR

  • e2e crossContextSerdeWorkflow - classes defined in step code are deserializable in workflow context

    Error: STACK_TRACE_ERROR

  • e2e stepFunctionAsStartArgWorkflow - step function reference passed as start() argument

    Error: STACK_TRACE_ERROR

  • e2e pages router addTenWorkflow via pages router

    Error: Failed to trigger workflow: http://localhost:3000/api/trigger-pages?workflowFile=workflows%2F99_e2e.ts&workflowFn

  • e2e pages router promiseAllWorkflow via pages router

    Error: Failed to trigger workflow: http://localhost:3000/api/trigger-pages?workflowFile=workflows%2F99_e2e.ts&workflowFn

  • e2e pages router sleepingWorkflow via pages router

    Error: Failed to trigger workflow: http://localhost:3000/api/trigger-pages?workflowFile=workflows%2F99_e2e.ts&workflowFn

View workflow run

@dustintownsend dustintownsend merged commit e79ff68 into main Feb 9, 2026
19 of 20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant