From 806714924c79130bcea9f7f7f756f29fb89a894f Mon Sep 17 00:00:00 2001 From: Branimir Georgiev <66906831+braboj@users.noreply.github.com> Date: Thu, 22 Oct 2026 00:50:10 +0300 Subject: [PATCH] refactor(concurrency): pitfalls as instructions, no bracket directive The pitfalls list names each fix as an instruction instead of a bold label, and "where possible" names its condition. The lead-in states the extension in prose instead of the directive's bracket form. Co-Authored-By: Claude Opus 5.5 --- templates/backend/concurrency.md | 30 +++++++++++++--------------- tests/baselines/template-quality.txt | 2 +- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/templates/backend/concurrency.md b/templates/backend/concurrency.md index b477d4db..f45e535b 100644 --- a/templates/backend/concurrency.md +++ b/templates/backend/concurrency.md @@ -1,9 +1,8 @@ # Backend — Concurrency [ID: backend-concurrency] -Universal rules for multi-threading, multi-processing, and async I/O. -Language-specific rules belong in the stack template via [EXTEND: -backend-concurrency]. +Rules for multi-threading, multi-processing and async I/O; a stack +template extends this one with its language's rules. ## When to use what @@ -39,24 +38,23 @@ CPU-bound work cannot be offloaded to a background job or worker process. ## Pitfalls -- **Deadlock**: two threads each waiting for a lock the other holds — - always acquire locks in a consistent order -- **Livelock**: threads repeatedly yielding to each other without making - progress — add backoff or a tiebreaker -- **Race condition**: outcome depends on scheduling order — - use a race detector during testing (e.g. `go test -race`, ThreadSanitizer) -- **Starvation**: low-priority work never gets scheduled — - bound queue sizes and use fair scheduling where possible -- **Thread-local state leakage**: in thread-pool or async contexts, - context (e.g. request ID, user identity) must be explicitly passed, - not stored in thread-locals +- Acquire locks in one consistent order, so no two threads deadlock + waiting on each other +- Add backoff or a tiebreaker where threads can livelock, yielding to each + other without progress +- Run a race detector in tests (e.g. `go test -race`, ThreadSanitizer) to + catch outcomes that depend on scheduling +- Bound queue sizes and schedule fairly where the runtime allows, so + low-priority work never starves +- Pass request context (request ID, user identity) explicitly in pools + and async code; never store it in thread-locals ## Observability - Log the concurrency model in use at service startup (thread pool size, event loop policy, worker count) -- Track thread/goroutine/task count as a metric — an unbounded growth - indicates a leak +- Track the thread, goroutine or task count as a metric; unbounded growth + is a leak - Alert on deadlock symptoms: requests timing out uniformly across all endpoints with no error in logs diff --git a/tests/baselines/template-quality.txt b/tests/baselines/template-quality.txt index 968ad08a..0dcc0306 100644 --- a/tests/baselines/template-quality.txt +++ b/tests/baselines/template-quality.txt @@ -5,7 +5,7 @@ templates/backend/api.md 94.9 templates/backend/auth.md 98.4 templates/backend/caching.md 100.0 -templates/backend/concurrency.md 94.8 +templates/backend/concurrency.md 98.1 templates/backend/database.md 92.0 templates/backend/edge.md 89.7 templates/backend/errors.md 91.7