ThreadsafeFn

Thread-safe wrapper around a JS function. T is the per-call payload type. Built via Callback.threadsafe(env, name, T) or Callback.threadsafeWithOptions.

const tsfn = try cb.threadsafe(env, "progress", u8);

threadsafe keeps the compatible unbounded Node-API queue. Use ThreadsafeOptions when .non_blocking must provide backpressure:

const tsfn = try cb.threadsafeWithOptions(env, "progress", u8, napi.ThreadsafeOptions{
    .max_queue_size = 64,
});

max_queue_size = 0 means unbounded; a positive value creates a bounded queue.

For the conceptual model and lifecycle rules, see Threadsafe functions.

T semantics

T valueBehavior
voidNo payload. JS callback is invoked with no arguments.
Any convertibleEach call sends a T. The bridge converts to JS via type conversion.

Methods

MethodReturnsPurpose
call(value, mode)!voidQueue a call from any thread. mode is .blocking/.non_blocking.
release()!voidRelease this thread's reference.
abort()!voidRelease and reject pending calls.
acquire()!voidRegister an additional thread.
ref(env)!voidKeep the event loop alive while this exists (default).
unref(env)!voidAllow the event loop to exit even if this exists.

call(value, mode)

try tsfn.call(42, .non_blocking);

mode is napi.ThreadsafeFn(T).Mode:

  • .blocking waits if a bounded queue is full.
  • .non_blocking returns error.QueueFull if a bounded queue is full.

An unbounded queue never reports QueueFull; choose a positive max_queue_size when producer backpressure is required.

For T = void, the call signature is try tsfn.call({}, mode).

call deep-copies slice-backed data and ordinary fixed-array pointers in supported structural payloads before enqueueing. Conversion failures and exceptions thrown by the JavaScript callback are forwarded exactly once through Node.js's uncaughtException path.

Payloads must be finite native values that the bridge can snapshot completely. Call-scoped handles (Env, Val, Callback, CallInfo, including nested occurrences) are compile errors because they cannot outlive their originating callback or cross a thread. Borrowed raw, many-item/sentinel, C, specially qualified, and recursively self-referential pointers are compile errors too; use a value, slice, fixed array, or stable ID instead.

Lifecycle pattern

const tsfn = try cb.threadsafe(env, "events", u32);

// each new thread:
try tsfn.acquire();
defer tsfn.release() catch {};

// when emitting:
try tsfn.call(value, .non_blocking);

// the original thread must release once at the end (it holds the
// initial refcount):
try tsfn.release();