File
Blob: src/workerd/io/AGENTS.md
src/workerd/io/
OVERVIEW
I/O lifecycle, per-request context, worker/isolate management, actor storage, consistency gates, and compatibility flags.
KEY CLASSES
| Class | File | Role |
|---|---|---|
IoContext |
io-context.{h,c++} |
Per-request god object; thread-local via IoContext::current() |
IoContext::IncomingRequest |
io-context.h |
Tracks one inbound request for metrics/tracing; actors have many per IoContext |
Worker |
worker.{h,c++} |
Ref-counted worker instance; owns Script + Isolate refs |
Worker::Isolate |
worker.h:337 |
V8 isolate wrapper; shared across workers with same config |
Worker::Script |
worker.h:250 |
Compiled script bound to an Isolate |
Worker::Lock |
worker.h:677 |
Synchronous V8 isolate lock (must hold to touch JS heap) |
Worker::AsyncLock |
worker.h:799 |
Fair async queue for acquiring Worker::Lock |
Worker::Actor |
worker.h:819 |
Durable Object instance; owns gates + cache + hibernation state |
ActorCache |
actor-cache.{h,c++} |
LRU write-back cache over RPC storage; ActorCacheOps base |
ActorSqlite |
actor-sqlite.{h,c++} |
SQLite-backed ActorCacheOps implementation |
InputGate / OutputGate |
io-gate.{h,c++} |
Consistency primitives for DO concurrent request handling |
IoOwn<T> / IoPtr<T> / ReverseIoOwn<T> |
io-own.{h,c++} |
Cross-heap smart pointers preventing KJ↔JS ref leaks |
WHERE TO LOOK
| Task | File(s) |
|---|---|
| Promise bridging KJ↔JS | io-context.h — awaitIo(), awaitJs() |
| Request lifecycle / subrequests | io-context.{h,c++}, worker-entrypoint.{h,c++} |
| Actor storage ops | actor-cache.h (ActorCacheOps), actor-sqlite.h, actor-storage.capnp |
| DO gate semantics | io-gate.{h,c++} — InputGate::CriticalSection, OutputGate::lockWhile() |
| Worker/isolate creation | worker.{h,c++}, worker-modules.{h,c++} |
| Metrics/logging hooks | observer.h — RequestObserver, IsolateObserver, ActorObserver |
| Tracing | trace.{h,c++,capnp}, trace-stream.{h,c++}, tracer.{h,c++} |
| Resource limits | limit-enforcer.h (abstract interface) |
| Timer scheduling | io-timers.{h,c++} |
| Hibernatable WebSockets | hibernation-manager.{h,c++} |
| Cap'n Proto schemas | worker-interface.capnp, actor-storage.capnp, container.capnp, trace.capnp |
CONVENTIONS
IoContext::current()— ambient thread-local access; only valid inside a requestawaitIo(js, kjPromise, func)bridges KJ→JS;funcruns under V8 lock.awaitIo(js, kjPromise)for identityawaitJs(js, jsPromise)bridges JS→KJaddObject(kj::Own<T>)returnsIoOwn<T>— the only safe way to store KJ I/O objects reachable from JS heap- Two-phase locking:
Worker::AsyncLock(fair queue) →Worker::Lock(V8 isolate lock) ActorCacheOpsmethods returnkj::OneOf<Result, kj::Promise<Result>>— sync when cached, async otherwiseOutputGate::lockWhile(promise)blocks outgoing responses until the promise resolvesInputGate::CriticalSectionmust succeed or permanently breaks the gate- Observer classes (
RequestObserver,IsolateObserver, etc.) have no-op defaults; all methods optional
ANTI-PATTERNS
- NEVER use
awaitIoLegacy()in new code — useawaitIo()with continuation awaitIoImplparameter ordering (promise by-value, func by-ref) is critical for exception safetyabortWhen()promises must never enter the V8 isolate- Cross-request I/O object access throws by design (IoOwn prevents this)