Files
atelier/domains/concurrency/patterns.md
T
Jon Chery 496303471d docs(milestone): complete v0.1 — initial framework
---ci---
project: atelier
phase: 7
milestone: v0.1
status: complete
phase_role: final
milestone_complete: true
requirements:
  covered: [ATELIER-01, ATELIER-02, ATELIER-03, ATELIER-04, ATELIER-05, ATELIER-06, ATELIER-07, ATELIER-08, ATELIER-09, ATELIER-10, ATELIER-11, ATELIER-12, ATELIER-13, ATELIER-14, ATELIER-15, ATELIER-16, ATELIER-17, ATELIER-18, ATELIER-19, ATELIER-20, ATELIER-21, ATELIER-22, ATELIER-23, ATELIER-24, ATELIER-25, ATELIER-26, ATELIER-27, ATELIER-28, ATELIER-29, ATELIER-30, ATELIER-31, ATELIER-32, ATELIER-33, ATELIER-34, ATELIER-35]
  partial: []
ship:
  milestone: v0.1
  type: NFR
  tag: v0.0.7
  merge: milestone/v0.1-atelier -> main
  release: https://git.cloudinit.dev/cloudinit-bot/atelier/releases/tag/v0.0.7
---/ci---

Milestone v0.1 — Initial Framework (NFR, complete).
8 core principles (C1-C8), 11 domains, 110 domain principles, 27 derived docs, 4 good + 3 bad examples, 4 language docs, full matrix, 3 review docs.
All 35 requirements covered. 7 patches (v0.0.0 pre-execution through v0.0.7 final). v0.0.7 IS the v0.1.0 milestone release.
2026-08-05 00:36:55 +00:00

2.7 KiB

Concurrency Patterns — Derived Rules

Derives from domains/concurrency/first-principles.md. Common concurrency patterns and when to use them.

Pattern 1: Message Passing (P5 Lock Minimization)

  • Threads/goroutines communicate via channels/queues, not shared memory.
  • "Don't communicate by sharing memory; share memory by communicating." (Go proverb)
  • Use when the data flows naturally in one direction. Avoids locks entirely.

Pattern 2: Read-Write Lock (P5 Lock Minimization)

  • Multiple readers, one writer. A RwLock allows concurrent reads, exclusive writes.
  • Use when reads vastly outnumber writes (e.g., a config cache).
  • Avoid when writes are frequent — the lock degrades to a mutex.

Pattern 3: Actor Model (P2 Single Responsibility)

  • Each actor owns its state. Actors communicate via messages. No shared state.
  • Use for isolated, long-lived workers (e.g., a session handler, a chat room).
  • Erlang/Akka/Pony are built on this. Implementable in any language with channels.

Pattern 4: Immutable Data Structures (P1 Immutability by Default)

  • Data is never mutated; a "change" creates a new value. Old values are safe to share.
  • Use in functional languages (Haskell, Clojure) or via persistent data structures (Immer.js).
  • Eliminates entire classes of races. The trade-off is allocation cost.

Pattern 5: Bounded Queue with Backpressure (P9 Bounded Queues)

  • A queue with a max size. When full, the producer is blocked or signaled.
  • Use to bound memory and propagate slowness from consumer to producer.
  • An unbounded queue hides a slow consumer until OOM. Always bound.

Pattern 6: Timeout on Every Block (P8 Timeout Discipline)

  • Every blocking call (lock acquire, queue send, HTTP request) has a timeout.
  • Use a timeout, not a forever-block. Forever is not a duration.
  • On timeout: cancel, retry, or fail. Do not hang.

Pattern 7: Cancellation Propagation (P7 Cancellation Support)

  • A cancellation signal propagates to all spawned work. Cancel the parent, the children stop.
  • Use context (context.Context in Go, AbortController in JS, CancellationToken in C#).
  • Cancellation is fast and complete. No orphaned goroutines/threads.

Pattern 8: Lock-Free Where Possible (P5)

  • Atomic operations (compare-and-swap) for simple state. No lock.
  • Use for counters, flags, simple pointers.
  • Avoid for complex state — lock-free code is subtle and easy to get wrong.

What Violates Concurrency Patterns

Violation Pattern
Shared mutable state with no lock (race, P1)
Unbounded queue P5 (OOM)
channel.send() with no timeout P6 (hang)
Spawned goroutine with no cancellation P7 (orphan)
A mutex held across an I/O call P3 (lock scope)
sync.Mutex for a counter P8 (use atomic)