## Engineering terms: concurrency

From Vibe Coding 101 (https://vibe-coding-101.brighteng.org/). When a request describes one of these problems, use the named technique, say its name, and run its check. Each term's page has the full entry and a prompt.

- **structured concurrency**: Child tasks finish within the lifetime of their enclosing operation. Use when: Background work survives the screen or request that started it. Do: Use scoped child tasks for related work. Define failure behavior and verify that cancellation reaches the children. Avoid: An unstructured task created inside a function is assumed to share its lifetime.
- **cooperative cancellation**: Work must observe cancellation and stop safely. Use when: An old search or upload keeps running after the user leaves. Do: Propagate cancellation, check it between work units, and prevent obsolete completions from updating current state. Avoid: A catch-all handler swallows cancellation and continues the operation. Worked example: https://vibe-coding-101.brighteng.org/examples/cancellation.md
- **actor isolation**: An actor protects its mutable state through an isolation boundary. Use when: Concurrent Swift tasks read and write the same mutable object. Do: Give the state one isolation owner and expose operations through it. Check assumptions across suspension points. Avoid: Assuming actor isolation makes a multi-step operation atomic across await.
- **actor reentrancy**: Other work can change actor state while an operation is suspended. Use when: An actor checks a condition, awaits a request, then acts on a stale assumption. Do: Recheck assumptions after await or reserve the operation before suspending. Test overlapping calls deliberately. Avoid: The test runs calls sequentially and never exercises the suspension window.
- **debounce**: Wait for a quiet interval before acting on repeated input. Use when: A search field sends a request on every keystroke. Do: Replace the pending action on new input. Handle cancellation and obsolete responses separately from the delay. Avoid: Debouncing input is treated as protection against out-of-order responses. Worked example: https://vibe-coding-101.brighteng.org/examples/debounce.md
- **backpressure**: Let consumer capacity constrain how fast producers send work. Use when: An event queue grows faster than the application can process it. Do: Select a bounded buffer and decide whether producers wait, reject, or drop specified work when it is full. Avoid: Dropping events silently when every event is required.
- **race condition**: An outcome depends on the timing of concurrent operations. Use when: Two overlapping operations can update the same state. Do: Identify the shared invariant and exercise competing operations with controlled ordering. Avoid: Fixing the visible order while leaving the underlying write unprotected. Worked example: https://vibe-coding-101.brighteng.org/examples/race-condition.md
- **event loop**: An event loop schedules work and callbacks around the runtime’s execution model. Use when: One expensive request freezes unrelated interactions or requests. Do: Profile the blocking segment and move or divide it according to the workload. Avoid: Replacing synchronous syntax with async syntax while keeping the same blocking computation.
- **mutex**: A mutex provides mutually exclusive access to a protected critical section. Use when: Concurrent operations must update shared memory without interleaving. Do: Choose the appropriate synchronization primitive and release it on every path. Avoid: Assuming an in-process mutex coordinates independent servers.
- **async vs parallel**: Asynchronous work can yield while waiting; parallel work executes simultaneously. Use when: I/O waits and CPU work need different execution strategies. Do: Classify the workload and choose bounded overlap or worker execution as appropriate. Avoid: Starting an unbounded task for every item and exhausting a downstream resource.
- **thread pool**: A thread pool reuses worker threads to execute submitted work. Use when: Blocking or CPU-heavy work must run without unbounded thread creation. Do: Size workers for the workload and dependencies, then define overload behavior. Avoid: Blocking pool workers on tasks that need the same exhausted pool to finish.
- **atomic operation**: An atomic operation takes effect indivisibly with respect to the relevant observers. Use when: Concurrent read-modify-write operations lose updates. Do: Choose the atomic primitive or database operation that protects the complete required update. Avoid: Assuming atomicity also supplies every required memory-ordering or transaction-isolation guarantee.
- **goroutine**: A goroutine is a lightweight unit of concurrent execution in Go. Use when: Go background work survives its request or becomes stuck on a channel. Do: Define who starts, stops, and waits for the goroutine, including blocked sends and receives. Avoid: Checking cancellation only after a channel operation that can block forever.
- **quorum**: Require a defined set of replicas or voters before accepting an operation. Use when: An operation must continue after some nodes fail without accepting conflicting decisions. Do: State membership, read/write counts, version rules, and failure assumptions. Check quorum loss and overlapping operations; distinguish acknowledgement counts from consensus. Avoid: A majority is common, but not every quorum is a majority and intersection alone is not consensus.
- **consensus**: Make participating nodes agree on decisions despite specified failures. Use when: Nodes must agree on a leader or committed log instead of inventing competing histories. Do: Use a proven implementation. Define crash versus Byzantine assumptions, membership changes, and commit rules. Check leader loss, partitions, and rejoining nodes. Avoid: Safety and progress are different properties. A safe system can stop accepting writes when it cannot decide.
- **CAP theorem**: During a network partition, atomic consistency and availability cannot both be guaranteed. Use when: You must decide what isolated replicas do when they cannot communicate. Do: Describe one partitioned read/write scenario. Choose whether to reject or delay an operation or allow potentially divergent results. Test that policy. Avoid: CAP availability differs from a monthly uptime percentage. ACID consistency means something else again.
- **snapshot isolation**: Read a stable transaction snapshot while detecting conflicting writes. Use when: A multi-query report mixes values from different committed moments. Do: Check the database’s snapshot boundary and conflict behavior. Test a stable report and a two-writer invariant. Use serializable execution or explicit coordination when required. Avoid: Isolation names vary by product. PostgreSQL Repeatable Read uses snapshot isolation, with stronger phantom protection than the SQL minimum.
- **MVCC**: Keep multiple row versions so reads can use a consistent snapshot. Use when: Readers and writers need concurrency without ordinary reads waiting on every write. Do: Document snapshot visibility and version cleanup. Check concurrent reads and writes, long-running transactions, and retained-version growth. Avoid: Explicit locks still exist; old snapshots can delay cleanup and increase storage use.
- **two-phase commit (2PC)**: Coordinate prepare and commit decisions across transaction participants. Use when: One transaction must commit or abort across multiple supporting resource managers. Do: Verify native participant support and a durable coordinator. Check crash recovery with a prepared participant and confirm unresolved transactions are monitored and resolved. Avoid: A coordinator failure can leave participants blocked. Arbitrary HTTP services are not automatically 2PC participants.
- **three-phase commit (3PC)**: Add a pre-commit phase to reduce blocking under restricted failure assumptions. Use when: You are comparing atomic commit protocols and their failure models. Do: Compare protocol states and assumptions using the cited recovery model. Analyze coordinator failure and a partition separately before selecting a supported implementation. Avoid: Classic 3PC does not make arbitrary partitions safe simply by adding timeouts. It is not a substitute for proven consensus-based coordination.
- **lock escalation**: Replace many fine-grained locks with a coarser lock in engines that support it. Use when: A large SQL Server update unexpectedly blocks unrelated rows in the same table. Do: Capture the lock-escalation event and blocking chain. Reduce the scan or batch size where appropriate, then verify lock footprint and transaction semantics. Avoid: A table lock can have other causes. Batching changes atomicity; do not split an all-or-nothing operation casually.
- **pessimistic locking**: Lock the protected rows before making a competing update. Use when: Several workers try to claim the same job or modify the same inventory row. Do: Keep read, decision, and write inside one transaction. Lock the necessary rows in consistent order. Test two competing sessions and lock timeouts. Avoid: Locking existing rows does not automatically protect every predicate or a missing row; constraints or stronger isolation may be needed.
- **dirty read**: Read a value another transaction has written but not committed. Use when: A report might include an update that is later rolled back. Do: Use two sessions: pause an uncommitted update, read from the other session, then roll back. Verify the behavior under the actual engine and isolation level. Avoid: Dirty reads differ from stale committed reads on a replica and from read skew across separate committed moments.
- **phantom read**: Repeat a predicate query and observe a changed set of matching rows. Use when: Two counts inside one transaction disagree after another transaction inserts a matching row. Do: Coordinate two sessions around the predicate read and competing insert. Check the chosen isolation level, then protect the invariant with constraints or appropriate transaction coordination. Avoid: An empty result locks no ordinary rows. Preventing phantoms alone does not establish serializability.
- **read skew**: Read related facts from different committed moments and combine an inconsistent view. Use when: A report reads an account before a transfer and the other account after it. Do: Interleave a transfer between the report’s two reads. Use a suitable transaction snapshot or one consistent query, then verify the reported invariant. Avoid: Read skew does not require a dirty read. Stable reads still do not prevent write skew in other transactions.
- **write skew**: Concurrent decisions update different rows and jointly violate an invariant. Use when: Two on-call doctors each see the other available and both go off duty. Do: Synchronize two decisions in a test. Use serializable execution with retries, a suitable constraint, or a shared lock boundary. Verify the invariant survives both attempted changes. Avoid: No lost update on a single row does not mean the transaction set is serializable.
- **throttling**: Bound how often work runs while events continue arriving. Use when: Continuous scroll events trigger expensive work faster than the UI needs it. Do: Choose leading and trailing behavior and a maximum rate. Check continuous events, the final value, and teardown using a controlled clock. Avoid: A client-side throttle does not enforce a server quota. Dropping intermediate work is unsafe when every event must be processed.
