-
Notifications
You must be signed in to change notification settings - Fork 1
Threading Contract
Canonical threading contract for OpenPit SDK handles across language bindings.
The SDK never spawns OS threads. Every public method executes on the OS thread that invoked it. The engine handle's threading capability follows from the chosen sync policy:
- Full sync - concurrent invocation on the same handle is safe, including calls for the same account. Locks protect individual storage accesses rather than serializing an entire engine call, so same-account pipelines may interleave between accesses.
- No sync - the handle stays on the OS thread that created the engine.
- Account sync - concurrent invocation on the same handle from multiple threads is safe iff the caller guarantees that calls for the same account are never concurrent (sharded workers, one channel per account hash, or any equivalent pinning scheme). Without that guarantee, concurrent invocation is undefined behavior. Sequential cross-thread invocation is always safe. The Go SDK ships an optional Async Engine helper that implements such per-account dispatch.
The pure-Rust AccountSyncEngine handle is deliberately Send + !Sync, so
concurrent invocation through one handle is rejected by the type system. The
caller-sharded rule above describes binding handles and dispatch adapters that
provide their own per-account routing. It is not a hidden serialization
guarantee supplied by FullSync.
Runtime migration of the caller between OS threads during one SDK call is supported (a goroutine moving across worker threads, a coroutine resuming on a different thread than it suspended on). Callbacks invoked by the SDK back into host code may run on a different OS thread than the caller, so callback code must not rely on thread-local OS state.
The user data fields on Reject, Order, ExecutionReport, and
AccountAdjustment are opaque caller tokens. The SDK never
inspects, dereferences, or frees them. Their lifetime, thread-safety, and
meaning are entirely the caller's responsibility.
Custom policies that need internal state across calls should use Storage - the synchronization-aware key-value abstraction that matches the engine's sync policy automatically and removes the need for external locking around policy state.