API ReferenceChannel API

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 slots
  • used — slots in use
  • free — slots available
  • errors, 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 or trySend always returns false or throws.
    • Solution: Ensure the channel is not full. Check slotSize and payload size. For async flows, use sendAsync with a timeout.
  • Problem: recv/tryRecv always returns null.
    • 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).
  • 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 or MPMC) 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.

Where to Go Next