Access the comprehensive SP8D Channel API reference for JavaScript and Node.js. Learn methods, options, diagnostics, troubleshooting, and best practices for lock-free, real-time, high-performance messaging.
SP8D Channel API Reference: Lock-Free Messaging for JavaScript & Node.js
The
Channel
API is at the heart of SP8D: It gives you explicit, lock-free, slot-driven control over cross-thread messaging—plus direct access to real-time diagnostics, segmentation, and backpressure handling.
Channel Creation
Create a channel for real-time, lock-free messaging. Use
createChannel
for new channels, attachChannel
to
connect in another thread.
createChannel(options): { channel, buffer }
Creates a new SP8D channel, returning both the API object and the underlying SharedArrayBuffer
.
Options:
slots
(number, required) — Number of slots in the ring buffer.slotSize
(number, required) — Max size (bytes) per payload.mode
(string: “SPSC” | “MPSC” | “MPMC”, optional) — Concurrency mode. Default:"SPSC"
.segments
(number) — Segments for increased scale. Default:1
.sweepTimeoutMs
(number) — Slot reclaim timeout (ms). Default:50
.
const { channel, buffer } = createChannel({
slots: 16,
slotSize: 64,
mode: "MPMC",
segments: 2,
});
attachChannel(buffer: SharedArrayBuffer): Channel
Use in a second thread/worker to attach to an existing channel’s buffer.
// In a worker thread/process
const channel = attachChannel(buffer);
Channel API: Core Methods
Methods are grouped by intent. Each group starts with a short intro and best practices. Scan, deep-dive, or jump to what you need.
Send Data
Use trySend
in high-frequency or non-critical paths to avoid
exceptions. Use send
when you must guarantee delivery or want to
catch errors.
send(payload: ArrayBufferView, producerId?: number): boolean
Enqueue a message. Throws if full or payload too large. Use for critical, must-succeed sends.
trySend(payload: ArrayBufferView, producerId?: number): boolean
Enqueue a message. Returns false
if full or payload too large—never throws. Use for non-blocking, best-effort sends.
sendAsync(payload: ArrayBufferView, producerId?: number, opts?): Promise<boolean>
Waits for a slot and sends. Supports timeout and abort. Use for async, backpressure-aware flows.
await channel.sendAsync(msg, myProducerId, { timeoutMs: 1000 });
Receive Data
Use recvAsync
for event-driven flows, and tryRecv
for polling or non-blocking loops.
recv(): Uint8Array | null
Synchronous receive. Returns null
if empty. Use for polling or tight loops.
const next = channel.recv();
if (next) process(next);
tryRecv(): Uint8Array | null
Non-throwing, non-blocking receive. Returns null
if empty.
const msg = channel.tryRecv();
if (msg) process(msg);
recvAsync(): Promise<Uint8Array | null>
Async receive. Waits for a message. Use for event-driven or awaitable flows.
const msg = await channel.recvAsync();
JSON Helpers
JSON helpers are for quick prototyping. For production, prefer binary serialization for performance and size.
sendJSON(obj: object, producerId?: number): boolean
Send a JSON-serializable object. Throws if full or payload too large.
recvJSON(): object | null
Receive a JSON-serialized object. Returns null
if empty or parse fails.
Channel State
Use full()
and empty()
to check channel status
before sending or receiving in tight loops.
full(): boolean
Returns true
if the channel is full (no slots available for sending).
empty(): boolean
Returns true
if the channel is empty (no slots available for reading).
Lifecycle & Control
After close()
, all send/recv methods will throw or return falsy.
Use closeAsync
for graceful shutdowns in async environments.
close(): void
Immediately closes the channel and all internal timers. Cleans up, resets all state. After close()
, send/recv throw or return falsy.
closeAsync(): Promise<void>
Gracefully closes the channel and waits for all background tasks to stop.
await channel.closeAsync();
reset(): void
Resets the channel to its initial state (empties all slots, resets counters). Does not reallocate the buffer.
channel.reset();
Diagnostics & Introspection
The channel can be used as an async iterator for idiomatic, event-driven
message consumption. Use stats()
and info()
for live
monitoring and debugging. Use validate()
in tests to catch
protocol errors early.
stats(): ChannelStats
Returns a snapshot object of channel usage and health metrics.
slots
— total slotsused
— slots in usefree
— slots availableerrors, conflicts, reclaimed
— counts of errors, producer/consumer collisions, and recovery sweeps
info(): string
Returns a human-readable string of the channel’s configuration (mode, size, segments).
validate(): void
Checks protocol invariants—throws if any slot is in an illegal state. Use in development/testing, not hot production loops.
[Symbol.asyncIterator](): AsyncIterator<Uint8Array, void>
The channel can be used as an async iterator:
for await (const msg of channel) {
// receive messages until channel.close()
}
Advanced: Slot Status Internals
For a complete explanation of slot state machine internals—including slot lifecycle, state transitions, atomic operations, and recovery—see the Slot State Machine documentation.
Diagnostics & Observability
Use diagnostics in development and staging to catch protocol issues early. Avoid running diagnostics in hot production loops unless you need live monitoring.
import { createChannelDiagnostics } from "@sp8d/diagnostics";
const diagnostics = createChannelDiagnostics(channel, 100);
diagnostics.onUpdate((stats) => {
console.log("SP8D Stats:", stats);
});
diagnostics.start();
See the Diagnostics Guide → for more.
Troubleshooting
Most issues stem from mismatched buffer sizes, incorrect slot counts, or using the wrong concurrency mode. Double-check your channel creation options. Common issues are listed below.
Common Issues & Solutions
- Problem:
send
ortrySend
always returnsfalse
or throws.- Solution: Ensure the channel is not full. Check
slotSize
and payload size. For async flows, usesendAsync
with a timeout.
- Solution: Ensure the channel is not full. Check
- Problem:
recv
/tryRecv
always returnsnull
.- Solution: The channel is empty. Confirm that producers are sending data and that you are not reading faster than writing.
- Problem:
attachChannel
throws or returns an unusable channel.- Solution: Make sure the
SharedArrayBuffer
is valid and matches the expected structure (slots, slotSize, segments).
- Solution: Make sure the
- Problem: Diagnostics report protocol errors or slot conflicts.
- Solution: Check that all threads use the correct concurrency mode (SPSC, MPSC, MPMC) and that no two producers/consumers are racing in SPSC mode.
- Problem: Channel appears to hang or deadlock.
- Solution: Avoid blocking the main thread. Use async methods and ensure all consumers/producers are running. For MPMC, ensure all parties are using unique IDs if required.
Performance & Concurrency Tips
For maximum throughput, tune slots
and slotSize
to
match your message rate and payload size. Use the minimal number of segments
needed for your concurrency model.
- Prefer
trySend
/tryRecv
in tight loops to avoid blocking. - Use
sendAsync
/recvAsync
for backpressure-aware, event-driven flows. - In high-concurrency scenarios, use the correct mode (
MPSC
orMPMC
) and avoid sharing producer/consumer IDs. - Monitor diagnostics in staging to catch contention or reclaim issues before production.
- Avoid frequent
reset()
in production; use it for test harnesses or controlled recovery only. - For lowest latency, keep
sweepTimeoutMs
low, but not zero—test for your workload.