DEV Community

Cover image for Pulse 2.0: Building a Deterministic Runtime for JavaScript Without Losing Your Mind
osvfelices
osvfelices

Posted on

Pulse 2.0: Building a Deterministic Runtime for JavaScript Without Losing Your Mind

(A real-world story of rewriting how async JavaScript should work)

If you’ve ever tried to build a truly concurrent system in JavaScript, you probably discovered three things very quickly:

  1. Promises are great until you actually need to orchestrate them.
  2. Promise.race has exactly one personality: chaos.
  3. Debugging async behaviour in Node feels like archaeology.

Pulse 2.0 started as a private experiment to answer a simple question:
Can we build a runtime for JavaScript applications that behaves predictably under load?

The answer became “yes”, but the road was much longer than expected.

After months of work, runtime audits, stress testing, and a full rewrite of HTTP handling, we now have something real: a deterministic runtime designed for modern backend apps.

Documentation:
https://osvfelices.github.io/pulse/

Why Pulse Exists

At its core, Pulse is about one idea:

Same inputs → Same outputs. Every time.
Even under concurrency. Even under load. Even when 100 tasks compete for channels.

Pulse introduces:

  • A deterministic scheduler
  • CSP-style channels
  • Select operations with strict ordering
  • Structured concurrency
  • A real HTTP server integrated with the scheduler
  • A debugger/inspector with predictable state snapshots

JavaScript was not built with this in mind, so Pulse had to build the missing pieces.

Deterministic Concurrency (Without Magic)

Pulse includes a scheduler that models async execution as a series of logical time steps, not wall-clock time.

Instead of letting Node decide task ordering, Pulse controls:

  • Task creation
  • Task wakeup
  • Channel send/receive events
  • Resolution of select operations
  • Cancellation cascades

The benefit is immediate:

If a program runs correctly once, it runs correctly every time.

We verified this with a 100-run determinism test. All runs produced identical output hashes.

Channels and Select: CSP Done Properly

Channels in Pulse behave like in Go:
blocking send, blocking receive, predictable ordering, safe close behaviour.

Example:

import { channel, spawn, sleep, select, selectCase } from 'pulselang/runtime';

await scheduler.run(async () => {
  const ch = channel(1);

  spawn(async () => {
    await sleep(50);
    await ch.send("hello");
  });

  const result = await select(
    selectCase(ch, 'recv', value => `received: ${value}`)
  );

  console.log(result);
});
Enter fullscreen mode Exit fullscreen mode

Even this simple snippet has a lot happening under the hood: task registration, channel waiters, deterministic state transitions, select resolution priority, etc.

Pulse ensures all of it happens in a fixed, reproducible order.

The HTTP Server Is Not Node’s HTTP

Pulse 1.x had a limitation:
HTTP handlers ran outside the deterministic scheduler.

Pulse 2.0 fixes this completely.

import { createServerWithScheduler, spawn, sleep } from 'pulselang/runtime';

const server = createServerWithScheduler(async (req, res) => {
  const value = await fetchSlowValue();

  spawn(async () => {
    await sleep(500);
    console.log("background work");
  });

  res.writeHead(200);
  res.end(JSON.stringify({ value }));
});
Enter fullscreen mode Exit fullscreen mode

Inside the handler you can use:

  • spawn
  • sleep
  • channels
  • select
  • structured concurrency

Each request gets its own isolated scheduler context.
Kill the request → all its tasks get cancelled automatically.

This is the kind of thing you normally need a custom Go server for.

Debugging Without Pain

Pulse includes an Inspector that produces consistent snapshots of the runtime:

  • task tree
  • channel states
  • select waiters
  • scheduler time
  • performance metrics

Everything is deterministic and serializable.

These snapshots feed into:

  • PRS (Pulse Runtime Server)
  • The future VSCode debugger extension

There is no “async black box”. Everything is visible.

Real-World Stress Testing

Pulse was tested with:

  • 1000 concurrent tasks
  • nested channel topologies
  • worker pool patterns
  • HTTP burst load
  • SSE realtime streams
  • batch processing apps
  • retry/backoff workflows

Results were consistent across runs, including under adversarial stress.

Pulse passed:

  • 98 runtime tests
  • 14 PRS tests
  • 12 debugger tests
  • 12 HTTP client tests
  • 100-run determinism
  • 232K jobs/sec worker benchmark

Memory remained stable, cancellation cascaded correctly, no deadlocks were observed.

What Pulse Is (And Isn’t)

Pulse is not a TypeScript competitor.
It’s not a new language with its own ecosystem.
It’s not trying to replace Go or Rust.

Pulse is:

  • A deterministic runtime
  • A concurrency model
  • A set of APIs that sit on top of JS
  • A scheduler that removes async randomness
  • A predictable foundation for real backend systems

If you’re building APIs, worker queues, realtime apps or orchestrators, Pulse gives you the tools JavaScript never shipped with.

Want to See It?

Documentation:
https://osvfelices.github.io/pulse/

Repository:
https://github.com/osvfelices/pulse

Final Thoughts

Pulse 2.0 is the result of many hours of testing, rewriting, auditing and verifying the same principle:

Concurrency doesn’t have to be unpredictable.

JavaScript developers deserve a runtime that behaves the same in development, staging and production.

If you want to try Pulse, clone the repo, run the examples, break things, open issues, or contribute ideas.

Pulse 2.0 is stable, battle-tested, and ready for real workloads.

Top comments (0)