(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:
- Promises are great until you actually need to orchestrate them.
- Promise.race has exactly one personality: chaos.
- 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);
});
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 }));
});
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)