Name the skill for what triggers it. Cite Wikipedia on capability-based security and ambient authority, and point newcomers to awesome-ocap. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
54 lines
2.8 KiB
Markdown
54 lines
2.8 KiB
Markdown
---
|
|
name: io-between-turns
|
|
description: I/O between turns — use when writing or reviewing code that reads or writes files, sockets, databases, or other shared external state; when choosing between sync and async APIs (readFileSync vs fs/promises, DatabaseSync, blocking calls); when someone says "sync I/O is a pointy instrument" or "I/O should be done between turns". Sync access is fine only for state that is local, prompt, and private to the one actor (e.g. a Durable Object's SQLite).
|
|
---
|
|
|
|
# I/O between turns
|
|
|
|
Event-loop concurrency (E, JavaScript, Workers) runs one **turn** at a
|
|
time: deliver one event, run the resulting calls to completion, then
|
|
take the next. A turn that never waits on the outside world is
|
|
isolated: nothing else can change what it can see while it runs. I/O
|
|
on shared or slow resources belongs **between** turns: issue it, end
|
|
the turn, and continue when the result arrives as a later event.
|
|
|
|
> "Execution proceeds by taking a pending-delivery from the queue,
|
|
> delivering its message to its object, and processing all the
|
|
> resulting immediate-calls in conventional call-return order. This is
|
|
> called a turn. … Because each event's turn runs to completion before
|
|
> the next is serviced, they are temporally isolated."
|
|
> — [Concurrency Among Strangers: Programming in E as Plan Coordination](https://agoric.com/assets/pdf/papers/concurrency-among-strangers.pdf),
|
|
> Miller, Tribble & Shapiro, TGC 2005, §5.2
|
|
|
|
> "The actual E system does provide synchronous file I/O operations.
|
|
> When these files are local, prompt, and private to the vat accessing
|
|
> them, this does not violate turn isolation, but since files may be
|
|
> remote, non-prompt, or shared, the availability of these synchronous
|
|
> I/O operations does violate the E model."
|
|
> — same paper, §6, footnote 5
|
|
|
|
(Mark Miller's thesis, *Robust Composition*, 2006, builds on this
|
|
paper.)
|
|
|
|
## the rule
|
|
|
|
- **Shared, remote, or slow state → async, between turns.** The
|
|
filesystem, the network, other processes' databases: use promise
|
|
APIs (`node:fs/promises`, `fetch`) and `await` them. No
|
|
`readFileSync`/`writeFileSync`, no blocking calls inside a turn.
|
|
- **Local, prompt, and private to the actor → sync is fine.** A
|
|
Durable Object's SQLite (`ctx.storage.sql`) is reachable only by its
|
|
own DO, so it is "more or less more RAM": synchronous access keeps
|
|
turn isolation.
|
|
- **Only a sync API exists, for shared state?** (e.g. `node:sqlite`'s
|
|
`DatabaseSync` on a file other processes may touch.) Keep it at the
|
|
program's edge and say why in a comment, so it doesn't read as a
|
|
precedent.
|
|
|
|
## see also
|
|
|
|
- [no-ambient-authority](../no-ambient-authority/SKILL.md): who gets to do I/O at
|
|
all (authority passed in, not ambient); this skill is about *when*.
|
|
- [silent-failures-are-evil](../silent-failures-are-evil/SKILL.md): an
|
|
awaited I/O failure still needs a trace.
|