@homericintelligence/athena-opencode 0.4.4 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -17
- package/package.json +2 -2
- package/plugin.js +20 -5
- package/skills/TECHNICAL_ENGLISH.md +78 -0
- package/skills/_cli.py +26 -18
- package/skills/_support/docs/dependency-resolution.md +192 -0
- package/skills/_support/docs/policies/development.md +117 -0
- package/skills/_support/docs/policies/evidence-integrity.md +40 -0
- package/skills/_support/docs/principles/README.md +542 -0
- package/skills/_support/docs/principles/details/p001-kiss.md +114 -0
- package/skills/_support/docs/principles/details/p002-yagni.md +109 -0
- package/skills/_support/docs/principles/details/p003-dry.md +126 -0
- package/skills/_support/docs/principles/details/p004-solid.md +165 -0
- package/skills/_support/docs/principles/details/p005-modularity.md +123 -0
- package/skills/_support/docs/principles/details/p006-principle-of-least-astonishment.md +115 -0
- package/skills/_support/docs/principles/details/p007-subtraction-over-addition.md +113 -0
- package/skills/_support/docs/principles/details/p008-understand-before-subtracting.md +115 -0
- package/skills/_support/docs/principles/details/p009-general-mechanisms-over-special-cases.md +108 -0
- package/skills/_support/docs/principles/details/p010-scope-fidelity.md +117 -0
- package/skills/_support/docs/principles/details/p011-minimal-coherent-change.md +128 -0
- package/skills/_support/docs/principles/details/p012-evidence-before-modification.md +115 -0
- package/skills/_support/docs/principles/details/p013-avoid-hasty-abstractions.md +112 -0
- package/skills/_support/docs/principles/details/p014-preserve-unrequested-behavior.md +110 -0
- package/skills/_support/docs/principles/details/p015-architecture-conformance.md +124 -0
- package/skills/_support/docs/principles/details/p016-separation-of-concerns.md +125 -0
- package/skills/_support/docs/principles/details/p017-high-cohesion-low-coupling.md +130 -0
- package/skills/_support/docs/principles/details/p018-information-hiding.md +128 -0
- package/skills/_support/docs/principles/details/p019-explicit-contracts.md +134 -0
- package/skills/_support/docs/principles/details/p020-executable-architecture.md +130 -0
- package/skills/_support/docs/principles/details/p021-evolutionary-and-reversible-design.md +126 -0
- package/skills/_support/docs/principles/details/p022-test-behavior-not-implementation.md +129 -0
- package/skills/_support/docs/principles/details/p023-parameterized-table-driven-testing.md +129 -0
- package/skills/_support/docs/principles/details/p024-boundary-value-testing.md +128 -0
- package/skills/_support/docs/principles/details/p025-property-based-testing-for-invariants.md +133 -0
- package/skills/_support/docs/principles/details/p026-regression-before-repair.md +134 -0
- package/skills/_support/docs/principles/details/p027-deterministic-and-hermetic-tests.md +128 -0
- package/skills/_support/docs/principles/details/p028-test-failure-paths.md +133 -0
- package/skills/_support/docs/principles/details/p029-generalize-error-policy-preserve-specific-cause.md +131 -0
- package/skills/_support/docs/principles/details/p030-nearest-responsible-error-boundary.md +133 -0
- package/skills/_support/docs/principles/details/p031-propagate-rather-than-swallow.md +131 -0
- package/skills/_support/docs/principles/details/p032-handle-once-preserve-causality.md +137 -0
- package/skills/_support/docs/principles/details/p033-state-safe-failure-semantics.md +140 -0
- package/skills/_support/docs/principles/details/p034-fail-fast.md +132 -0
- package/skills/_support/docs/principles/details/p035-fail-secure-fail-closed.md +137 -0
- package/skills/_support/docs/principles/details/p036-graceful-degradation.md +137 -0
- package/skills/_support/docs/principles/details/p037-idempotency-before-retry.md +139 -0
- package/skills/_support/docs/principles/details/p038-bounded-retry.md +145 -0
- package/skills/_support/docs/principles/details/p039-bounded-waiting.md +151 -0
- package/skills/_support/docs/principles/details/p040-bounded-resources.md +138 -0
- package/skills/_support/docs/principles/details/p041-backpressure-and-load-shedding.md +141 -0
- package/skills/_support/docs/principles/details/p042-fault-isolation-bulkheads.md +140 -0
- package/skills/_support/docs/principles/details/p043-circuit-breakers.md +148 -0
- package/skills/_support/docs/principles/details/p044-atomicity-where-possible.md +141 -0
- package/skills/_support/docs/principles/details/p045-compensation-where-atomicity-is-impossible.md +163 -0
- package/skills/_support/docs/principles/details/p046-resumability.md +138 -0
- package/skills/_support/docs/principles/details/p047-observability-is-part-of-correctness.md +134 -0
- package/skills/_support/docs/principles/details/p048-secure-by-design.md +132 -0
- package/skills/_support/docs/principles/details/p049-secure-by-default.md +126 -0
- package/skills/_support/docs/principles/details/p050-least-privilege.md +123 -0
- package/skills/_support/docs/principles/details/p051-complete-mediation.md +124 -0
- package/skills/_support/docs/principles/details/p052-separation-of-duties.md +129 -0
- package/skills/_support/docs/principles/details/p053-validate-at-trust-boundaries.md +126 -0
- package/skills/_support/docs/principles/details/p054-defense-in-depth.md +135 -0
- package/skills/_support/docs/principles/details/p055-minimize-attack-surface.md +133 -0
- package/skills/_support/docs/principles/details/p056-secrets-stay-out-of-code-and-context.md +137 -0
- package/skills/_support/docs/principles/details/p057-supply-chain-integrity.md +135 -0
- package/skills/_support/docs/principles/details/p058-bounded-agent-authority.md +137 -0
- package/skills/_support/docs/principles/details/p059-data-is-not-instruction.md +130 -0
- package/skills/_support/docs/principles/details/p060-constrain-sub-agents.md +136 -0
- package/skills/_support/docs/principles/details/p061-separate-decision-from-high-impact-execution.md +131 -0
- package/skills/_support/docs/principles/details/p062-human-approval-for-irreversible-or-high-risk-actions.md +129 -0
- package/skills/_support/docs/principles/details/p063-requirement-to-code-traceability.md +116 -0
- package/skills/_support/docs/principles/details/p064-requirement-to-test-traceability.md +116 -0
- package/skills/_support/docs/principles/details/p065-verify-before-claiming-completion.md +129 -0
- package/skills/_support/docs/principles/details/p066-preserve-existing-work.md +114 -0
- package/skills/_support/docs/principles/details/p067-no-test-cheating.md +126 -0
- package/skills/_support/docs/principles/details/p068-no-validation-bypass.md +119 -0
- package/skills/_support/docs/principles/details/p069-independent-review-for-high-risk-changes.md +129 -0
- package/skills/_support/docs/principles/details/p070-code-health-must-not-regress.md +116 -0
- package/skills/_support/docs/principles/details/p071-consistency-over-personal-preference.md +117 -0
- package/skills/_support/docs/principles/details/p072-technical-evidence-over-preference.md +122 -0
- package/skills/_support/docs/principles/details/p073-optimize-only-with-evidence.md +123 -0
- package/skills/_support/docs/principles/details/p074-prefer-existing-mechanisms.md +121 -0
- package/skills/_support/docs/principles/details/p075-make-invalid-states-hard-to-represent.md +128 -0
- package/skills/_support/docs/principles/details/p076-parse-then-validate-then-operate.md +133 -0
- package/skills/_support/docs/principles/details/p077-separate-policy-from-mechanism.md +112 -0
- package/skills/_support/docs/principles/details/p078-single-source-of-truth.md +131 -0
- package/skills/_support/docs/principles/details/p079-explicit-ownership-and-lifetimes.md +124 -0
- package/skills/_support/docs/principles/details/p080-make-concurrency-deliberate.md +122 -0
- package/skills/_support/docs/principles/details/p081-forward-progress-with-safety.md +125 -0
- package/skills/_support/docs/principles/details/p082-design-for-cancellation.md +133 -0
- package/skills/_support/docs/principles/details/p083-irreversible-actions-last.md +124 -0
- package/skills/_support/docs/principles/details/p084-prefer-local-reasoning.md +131 -0
- package/skills/_support/docs/principles/details/p085-explicit-is-better-than-implicit.md +123 -0
- package/skills/_support/docs/principles/details/p086-readability-counts.md +113 -0
- package/skills/_support/docs/principles/details/p087-comments-explain-why-code-explains-what.md +120 -0
- package/skills/_support/docs/principles/details/p088-delete-dead-code.md +125 -0
- package/skills/_support/docs/principles/details/p089-delete-obsolete-configuration-and-dependencies.md +125 -0
- package/skills/_support/docs/principles/details/p090-prefer-negative-code.md +134 -0
- package/skills/_support/docs/principles/details/p091-test-driven-development.md +149 -0
- package/skills/_support/docs/review/README.md +59 -0
- package/skills/_support/docs/review/behavior-first-testing.md +73 -0
- package/skills/_support/docs/review/common.md +365 -0
- package/skills/_support/docs/review/design-docs.md +74 -0
- package/skills/_support/docs/review/issue-planning.md +220 -0
- package/skills/_support/docs/review/language-routing.md +141 -0
- package/skills/_support/docs/review/repository-scorecard.md +170 -0
- package/skills/advise/SKILL.md +102 -40
- package/skills/advise/scripts/list_retrievable_skills.py +3 -3
- package/skills/brainstorm/SKILL.md +167 -76
- package/skills/change-review/SKILL.md +99 -43
- package/skills/change-review/references/scope-resolution.md +70 -41
- package/skills/change-review/scripts/resolve_scope.py +119 -73
- package/skills/finalize-plan/SKILL.md +208 -100
- package/skills/git-worktrees/SKILL.md +108 -59
- package/skills/git-worktrees/scripts/prepare_worktree.py +16 -10
- package/skills/issue-review/SKILL.md +143 -47
- package/skills/learn/SKILL.md +284 -162
- package/skills/myrmidon-swarm/SKILL.md +136 -61
- package/skills/plan-issue/SKILL.md +129 -47
- package/skills/pr-review/SKILL.md +170 -71
- package/skills/pr-review/references/criteria.md +61 -14
- package/skills/pr-review/references/delivery.md +159 -80
- package/skills/pr-review/references/evidence.md +268 -139
- package/skills/pr-review/references/prevalidated.md +91 -48
- package/skills/pr-review/scripts/collect_evidence.py +211 -140
- package/skills/pr-review/scripts/diff_context.py +6 -4
- package/skills/pr-review/scripts/materialize_snapshot.py +112 -120
- package/skills/pr-review/scripts/pr_identity.py +27 -15
- package/skills/pr-review/scripts/resolve_pr.py +53 -31
- package/skills/repo-review/SKILL.md +209 -87
- package/skills/systematic-debugging/SKILL.md +195 -131
- package/skills/systematic-debugging/scripts/repository_evidence.py +9 -4
- package/skills/test-driven-development/SKILL.md +134 -53
- package/skills/tidy/SKILL.md +97 -33
- package/skills/tidy/scripts/run_tidy.py +3 -3
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# P041 — Backpressure and Load Shedding
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
When demand is near capacity or is more than capacity, prevent system overload with a clear control response.
|
|
6
|
+
**Backpressure** tells producers to decrease rate or concurrency.
|
|
7
|
+
|
|
8
|
+
**Load shedding** rejects or removes selected work to decrease admitted work. The
|
|
9
|
+
two controls prevent unlimited queues and resource exhaustion during overload.
|
|
10
|
+
|
|
11
|
+
**Aliases:** flow control, overload signaling, admission shedding
|
|
12
|
+
|
|
13
|
+
## Provenance
|
|
14
|
+
|
|
15
|
+
**Classification:** established principle.
|
|
16
|
+
|
|
17
|
+
Flow-control and data-stream systems give specified meanings to backpressure. Practitioners use
|
|
18
|
+
load shedding in overload control. Athena uses these tools but does not give them the same
|
|
19
|
+
meaning.
|
|
20
|
+
|
|
21
|
+
## Decision rule
|
|
22
|
+
|
|
23
|
+
Before saturation, limit upstream demand to sustainable capacity. If demand is more than capacity,
|
|
24
|
+
reject work with low cost and a clear result. Do not accept unlimited work because there is a queue.
|
|
25
|
+
|
|
26
|
+
## How to apply
|
|
27
|
+
|
|
28
|
+
- Find the bottleneck. Examples are concurrency, queue depth, CPU, memory, and downstream
|
|
29
|
+
quota.
|
|
30
|
+
- Give standard overload signals. Examples are demand pause, finite credits, HTTP 429 or 503,
|
|
31
|
+
and safe retry guidance.
|
|
32
|
+
- Send downstream backpressure to producers. After a backpressure signal, do not retry with no wait.
|
|
33
|
+
- Before overload stops the system, reject work. When requests have different value or cost, apply
|
|
34
|
+
specified priority and fairness rules.
|
|
35
|
+
- Make rejection cost less than admitted work. If input parsing has a high cost, admit or reject
|
|
36
|
+
the request before parsing.
|
|
37
|
+
- Monitor saturation, rejection rate, principals that receive rejections, tail latency, and recovery.
|
|
38
|
+
- Do tests of continuous overload, bursts, callers with retry policies, and recovery after load
|
|
39
|
+
decreases.
|
|
40
|
+
|
|
41
|
+
## Diagram
|
|
42
|
+
|
|
43
|
+
```mermaid
|
|
44
|
+
flowchart TD
|
|
45
|
+
A["Demand is near capacity"] --> B{"Can the producer decrease demand?"}
|
|
46
|
+
B -- Yes --> C["Send a backpressure signal"]
|
|
47
|
+
C --> D["Set demand to sustainable capacity"]
|
|
48
|
+
B -- No --> E["Apply priority and fairness rules"]
|
|
49
|
+
E --> F["When demand is more than capacity, reject work with low cost"]
|
|
50
|
+
F --> G["Keep service for admitted work"]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Language examples
|
|
54
|
+
|
|
55
|
+
Each example rejects work at capacity and gives a retry signal.
|
|
56
|
+
|
|
57
|
+
### Python
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
def admit(request, slots):
|
|
61
|
+
if not slots.acquire(blocking=False):
|
|
62
|
+
return Response(status=503, headers={"Retry-After": "1"})
|
|
63
|
+
try:
|
|
64
|
+
return serve(request)
|
|
65
|
+
finally:
|
|
66
|
+
slots.release()
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Rust
|
|
70
|
+
|
|
71
|
+
```rust
|
|
72
|
+
fn admit(request: Request, slots: &Semaphore) -> Response {
|
|
73
|
+
let Ok(_permit) = slots.try_acquire() else {
|
|
74
|
+
return Response::retry_after(503, 1);
|
|
75
|
+
};
|
|
76
|
+
serve(request)
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Boundaries and tensions
|
|
81
|
+
|
|
82
|
+
A buffer can absorb a short demand mismatch. If the buffer has no limit or producers receive no
|
|
83
|
+
capacity signal, it gives no backpressure. Apply [P040](p040-bounded-resources.md) to all queues.
|
|
84
|
+
|
|
85
|
+
If callers apply [P038](p038-bounded-retry.md), a retry response can help. If callers do not apply
|
|
86
|
+
it, rejection can cause a retry storm.
|
|
87
|
+
|
|
88
|
+
Load shedding is a control that rejects selected work. [P036](p036-graceful-degradation.md) gives a
|
|
89
|
+
reduced but correct result. A system can use the two controls together.
|
|
90
|
+
|
|
91
|
+
The two controls cannot operate without security controls or change a necessary correctness
|
|
92
|
+
contract without a report.
|
|
93
|
+
|
|
94
|
+
## Examples
|
|
95
|
+
|
|
96
|
+
### Positive application
|
|
97
|
+
|
|
98
|
+
A service is near its active request limit. It returns HTTP 503 with finite retry guidance for new
|
|
99
|
+
refresh requests with low priority. It keeps reserved capacity for very important writes.
|
|
100
|
+
|
|
101
|
+
After latency becomes stable, the service makes admission available again in steps.
|
|
102
|
+
|
|
103
|
+
### Misuse or counterexample
|
|
104
|
+
|
|
105
|
+
A consumer acknowledges messages immediately and keeps them in an unlimited local list. The
|
|
106
|
+
producer receives no pressure signal. The process uses more memory until it stops.
|
|
107
|
+
|
|
108
|
+
### Athena or agent workflow
|
|
109
|
+
|
|
110
|
+
A coordinator at its concurrency limit keeps only a finite task queue. It defers or rejects
|
|
111
|
+
low-priority tasks and tells the user about the constraint. It does not use all host or token capacity.
|
|
112
|
+
|
|
113
|
+
## Related principles
|
|
114
|
+
|
|
115
|
+
- [P036 — Graceful Degradation](p036-graceful-degradation.md)
|
|
116
|
+
- [P038 — Bounded Retry](p038-bounded-retry.md)
|
|
117
|
+
- [P040 — Bounded Resources](p040-bounded-resources.md)
|
|
118
|
+
- [P042 — Fault Isolation / Bulkheads](p042-fault-isolation-bulkheads.md)
|
|
119
|
+
|
|
120
|
+
## References
|
|
121
|
+
|
|
122
|
+
### Source information
|
|
123
|
+
|
|
124
|
+
- [Reactive Manifesto 2.0 (2014)](https://www.reactivemanifesto.org/) — practitioner statement that
|
|
125
|
+
connects message-based flow control, queue observation, and backpressure. It is
|
|
126
|
+
not the source of flow control.
|
|
127
|
+
|
|
128
|
+
### Applicable information
|
|
129
|
+
|
|
130
|
+
- [Reactive Streams 1.0.4](https://www.reactive-streams.org/) — specification and compatibility
|
|
131
|
+
kit for asynchronous stream operations with nonblocking backpressure.
|
|
132
|
+
- [Google SRE, Addressing Cascading Failures](https://sre.google/sre-book/addressing-cascading-failures/)
|
|
133
|
+
— production guidance for load shedding, overload signals, finite queues, and reduced results.
|
|
134
|
+
|
|
135
|
+
### More information
|
|
136
|
+
|
|
137
|
+
- [Microsoft Azure, Throttling pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/throttling)
|
|
138
|
+
— guidance for load shedding before saturation, caller signals, fairness, and backpressure in a
|
|
139
|
+
call chain.
|
|
140
|
+
|
|
141
|
+
[Back to the engineering principles catalog](../README.md#p041)
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# P042 — Fault Isolation / Bulkheads
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
Partition workloads, dependencies, tenants, and resource pools. Failure or exhaustion in one
|
|
6
|
+
partition must not use capacity or corrupt state for a different partition.
|
|
7
|
+
|
|
8
|
+
Isolation limits a system-wide failure to a finite local failure.
|
|
9
|
+
|
|
10
|
+
**Aliases:** bulkhead pattern, failure domains, cell-based isolation, blast-radius containment
|
|
11
|
+
|
|
12
|
+
## Provenance
|
|
13
|
+
|
|
14
|
+
**Classification:** established principle.
|
|
15
|
+
|
|
16
|
+
Ship design is the source of the name. Michael Nygard's *Release It!* made the bulkhead pattern
|
|
17
|
+
known to many software engineers. Fault isolation was available before this pattern name.
|
|
18
|
+
|
|
19
|
+
## Decision rule
|
|
20
|
+
|
|
21
|
+
Before components share resources, compare their failure risks, criticality, owners, and consumers.
|
|
22
|
+
If shared failure can violate an objective, use isolated capacity and state boundaries.
|
|
23
|
+
|
|
24
|
+
## How to apply
|
|
25
|
+
|
|
26
|
+
- Set failure domains from business criticality and dependency paths. Do not use only
|
|
27
|
+
deployment topology.
|
|
28
|
+
- If shared exhaustion can violate objectives, use different concurrency pools, queues, connection
|
|
29
|
+
pools, quotas, processes, accounts, regions, or credentials.
|
|
30
|
+
- Reserve sufficient capacity for health, recovery, and very important traffic in each applicable
|
|
31
|
+
partition.
|
|
32
|
+
- Isolate the data plane from control-plane failure. Do not let one tenant use all shared
|
|
33
|
+
capacity.
|
|
34
|
+
- Monitor each partition independently. Keep an aggregate view of system health.
|
|
35
|
+
- Do tests of exhaustion and failure in one partition. Make sure that different partitions continue.
|
|
36
|
+
|
|
37
|
+
## Diagram
|
|
38
|
+
|
|
39
|
+
```mermaid
|
|
40
|
+
flowchart TD
|
|
41
|
+
A["Classify the failure risk of each workload"] --> B["Give each workload an isolated resource pool with finite capacity"]
|
|
42
|
+
B --> C1["Partition A serves its workload"]
|
|
43
|
+
B --> C2["Partition B serves its workload"]
|
|
44
|
+
C1 --> D{"Does Partition A have a failure or use all pool capacity?"}
|
|
45
|
+
D -- Yes --> E["Contain the failure in Partition A"]
|
|
46
|
+
D -- No --> G["Continue service in Partition A"]
|
|
47
|
+
E --> F["Partition B keeps capacity and state"]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Language examples
|
|
51
|
+
|
|
52
|
+
Each example uses a different concurrency pool for each dependency.
|
|
53
|
+
|
|
54
|
+
### Python
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
pools = {"search": Semaphore(8), "billing": Semaphore(2)}
|
|
58
|
+
|
|
59
|
+
def call(name, request):
|
|
60
|
+
pool = pools[name]
|
|
61
|
+
if not pool.acquire(blocking=False):
|
|
62
|
+
return IsolatedOverload(name)
|
|
63
|
+
try:
|
|
64
|
+
return clients[name].send(request)
|
|
65
|
+
finally:
|
|
66
|
+
pool.release()
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Rust
|
|
70
|
+
|
|
71
|
+
```rust
|
|
72
|
+
fn call(kind: Kind, services: &Services, request: Request) -> Result<Response, Error> {
|
|
73
|
+
let partition = match kind {
|
|
74
|
+
Kind::Search => &services.search,
|
|
75
|
+
Kind::Billing => &services.billing,
|
|
76
|
+
};
|
|
77
|
+
let permit = partition.pool.try_acquire().map_err(|_| Error::IsolatedOverload)?;
|
|
78
|
+
let result = partition.client.send(request);
|
|
79
|
+
drop(permit);
|
|
80
|
+
result
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Boundaries and tensions
|
|
85
|
+
|
|
86
|
+
Isolation decreases available capacity and adds work to system operation. It can also decrease efficiency. If there is
|
|
87
|
+
no specified failure mode or service objective, do not make a partition.
|
|
88
|
+
|
|
89
|
+
A logical label is not a bulkhead when all partitions share one unlimited queue, connection pool,
|
|
90
|
+
or credential.
|
|
91
|
+
|
|
92
|
+
[P040](p040-bounded-resources.md) sets a limit for each pool. [P041](p041-backpressure-and-load-shedding.md)
|
|
93
|
+
controls admission at capacity, and [P043](p043-circuit-breakers.md) stops calls to a dependency that failed.
|
|
94
|
+
Use these controls together. They do not replace each other.
|
|
95
|
+
|
|
96
|
+
## Examples
|
|
97
|
+
|
|
98
|
+
### Positive application
|
|
99
|
+
|
|
100
|
+
Calls to three downstream services use different connection pools and concurrency pools. One service
|
|
101
|
+
stalls and uses all capacity in its pool. Health checks and calls to other services stay available.
|
|
102
|
+
|
|
103
|
+
### Misuse or counterexample
|
|
104
|
+
|
|
105
|
+
Tenants have different labels but share one executor and an unlimited queue. One tenant sends
|
|
106
|
+
work with high cost and uses all capacity. The labels give no fault isolation.
|
|
107
|
+
|
|
108
|
+
### Athena or agent workflow
|
|
109
|
+
|
|
110
|
+
Different subagents receive finite task scopes and different write targets. One specialist that fails
|
|
111
|
+
does not use all delegation slots or corrupt a different specialist result.
|
|
112
|
+
|
|
113
|
+
## Related principles
|
|
114
|
+
|
|
115
|
+
- [P036 — Graceful Degradation](p036-graceful-degradation.md)
|
|
116
|
+
- [P040 — Bounded Resources](p040-bounded-resources.md)
|
|
117
|
+
- [P041 — Backpressure and Load Shedding](p041-backpressure-and-load-shedding.md)
|
|
118
|
+
- [P043 — Circuit Breakers](p043-circuit-breakers.md)
|
|
119
|
+
|
|
120
|
+
## References
|
|
121
|
+
|
|
122
|
+
### Source information
|
|
123
|
+
|
|
124
|
+
- [Michael T. Nygard, *Release It!*, second edition](https://pragprog.com/titles/mnee2/release-it-second-edition/)
|
|
125
|
+
— a source that made bulkheads and other stability patterns known to many software engineers. Physical
|
|
126
|
+
bulkheads are older than computers.
|
|
127
|
+
|
|
128
|
+
### Applicable information
|
|
129
|
+
|
|
130
|
+
- [Microsoft Azure, Bulkhead pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/bulkhead)
|
|
131
|
+
— applicable guidance for different service instances and resource pools that isolate failure
|
|
132
|
+
cascades.
|
|
133
|
+
|
|
134
|
+
### More information
|
|
135
|
+
|
|
136
|
+
- [Microsoft Azure Well-Architected reliability patterns](https://learn.microsoft.com/en-us/azure/well-architected/reliability/design-patterns)
|
|
137
|
+
— includes bulkheads, throttles, retries, and circuit breakers as related reliability
|
|
138
|
+
controls.
|
|
139
|
+
|
|
140
|
+
[Back to the engineering principles catalog](../README.md#p042)
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# P043 — Circuit Breakers
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
A circuit breaker monitors calls to a dependency. After measurements show continuous failure, it opens
|
|
6
|
+
and rejects new calls without contact with that dependency.
|
|
7
|
+
|
|
8
|
+
After a controlled recovery interval, it admits a finite probe set in a half-open state. A failed
|
|
9
|
+
probe opens the breaker again. The breaker closes only after sufficient probes succeed.
|
|
10
|
+
|
|
11
|
+
**Aliases:** dependency circuit breaker, open/half-open/closed breaker
|
|
12
|
+
|
|
13
|
+
## Provenance
|
|
14
|
+
|
|
15
|
+
**Classification:** established principle.
|
|
16
|
+
|
|
17
|
+
Michael Nygard made the software pattern known to many engineers in *Release It!*. The electrical
|
|
18
|
+
circuit breaker is the source of the software-pattern name. Related failure controls were available
|
|
19
|
+
before the software pattern.
|
|
20
|
+
|
|
21
|
+
## Decision rule
|
|
22
|
+
|
|
23
|
+
If calls use resources without a caller result or overload a dependency, stop calls for a finite
|
|
24
|
+
interval. If calls can cause system failure, use the same control. Do a recovery test with
|
|
25
|
+
a finite probe set.
|
|
26
|
+
|
|
27
|
+
## How to apply
|
|
28
|
+
|
|
29
|
+
- Put the breaker at a failure-prone dependency boundary. If local business logic does not have
|
|
30
|
+
that failure risk, do not put the breaker at its boundary.
|
|
31
|
+
- Use the dependency contract and measurements to select failure signals, observation
|
|
32
|
+
window, threshold, open time, and recovery criteria.
|
|
33
|
+
- Give breaker state the correct scope. A global breaker can disable available partitions. A
|
|
34
|
+
breaker for one request does not have sufficient data from previous calls.
|
|
35
|
+
- While the breaker is open, immediately return a clear failure or a specified fallback.
|
|
36
|
+
- While the breaker is in the half-open state, use only a finite probe set. Prevent a recovery surge.
|
|
37
|
+
- Record state transitions, rejected calls, probe results, and dependency identity.
|
|
38
|
+
- Do tests of state oscillation, slow calls, recovery of only some calls, and interactions with retries.
|
|
39
|
+
|
|
40
|
+
## Diagram
|
|
41
|
+
|
|
42
|
+
```mermaid
|
|
43
|
+
flowchart LR
|
|
44
|
+
A["Closed: let calls continue"] -->|"Failure threshold met"| B["Open: reject calls"]
|
|
45
|
+
B -->|"Recovery interval expires"| C["Half-open: use finite probes"]
|
|
46
|
+
C -->|"Recovery criteria met"| A
|
|
47
|
+
C -->|"A probe fails"| B
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Language examples
|
|
51
|
+
|
|
52
|
+
Each example records dependency failures and calls that succeed, but does not include permanent
|
|
53
|
+
request errors in breaker state.
|
|
54
|
+
|
|
55
|
+
### Python
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
def call(breaker, client):
|
|
59
|
+
if (permit := breaker.try_acquire()) is None:
|
|
60
|
+
return Unavailable()
|
|
61
|
+
result = client.request()
|
|
62
|
+
if result.ok:
|
|
63
|
+
outcome = BreakerOutcome.SUCCESS
|
|
64
|
+
elif result.is_dependency_failure:
|
|
65
|
+
outcome = BreakerOutcome.FAILURE
|
|
66
|
+
else:
|
|
67
|
+
outcome = BreakerOutcome.IGNORED
|
|
68
|
+
permit.complete(outcome)
|
|
69
|
+
return result
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Rust
|
|
73
|
+
|
|
74
|
+
```rust
|
|
75
|
+
fn call(breaker: &Breaker, client: &Client) -> Result<Response, Error> {
|
|
76
|
+
let permit = breaker.try_acquire().ok_or(Error::Unavailable)?;
|
|
77
|
+
let result = client.request();
|
|
78
|
+
let outcome = match &result {
|
|
79
|
+
Ok(_) => BreakerOutcome::Success,
|
|
80
|
+
Err(error) if error.is_dependency_failure() => BreakerOutcome::Failure,
|
|
81
|
+
Err(_) => BreakerOutcome::Ignored,
|
|
82
|
+
};
|
|
83
|
+
permit.complete(outcome);
|
|
84
|
+
result
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Boundaries and tensions
|
|
89
|
+
|
|
90
|
+
A breaker is not a retry policy. Use [P038](p038-bounded-retry.md) for isolated transient errors.
|
|
91
|
+
The breaker prevents more calls during continuous failure. A timeout from
|
|
92
|
+
[P039](p039-bounded-waiting.md) limits the time for each call after breaker approval.
|
|
93
|
+
|
|
94
|
+
If a small number of failures opens a breaker, the breaker can cause unavailability that is not necessary. If
|
|
95
|
+
too many failures occur before it opens, it can cause a failure cascade.
|
|
96
|
+
|
|
97
|
+
[P042](p042-fault-isolation-bulkheads.md) limits the effect before the breaker opens.
|
|
98
|
+
Use [P036](p036-graceful-degradation.md) for each fallback response.
|
|
99
|
+
|
|
100
|
+
## Examples
|
|
101
|
+
|
|
102
|
+
### Positive application
|
|
103
|
+
|
|
104
|
+
A client records timeouts in an observation window. At its tested threshold, the
|
|
105
|
+
dependency-specific breaker opens. It rejects calls for a finite interval.
|
|
106
|
+
|
|
107
|
+
Before the breaker makes traffic available again, it uses a small number of probes.
|
|
108
|
+
|
|
109
|
+
### Misuse or counterexample
|
|
110
|
+
|
|
111
|
+
One validation error opens an application-wide breaker for all tenants and endpoints. The error is
|
|
112
|
+
a permanent request defect, not a dependency failure. The breaker disables available traffic.
|
|
113
|
+
|
|
114
|
+
### Athena or agent workflow
|
|
115
|
+
|
|
116
|
+
A dependency tool returns measured service-failure results. After a finite threshold, an Athena workflow
|
|
117
|
+
stops calls to that tool and gives an unavailable-capability result.
|
|
118
|
+
|
|
119
|
+
It does not use more tool calls or give a success result for a missing result.
|
|
120
|
+
|
|
121
|
+
## Related principles
|
|
122
|
+
|
|
123
|
+
- [P036 — Graceful Degradation](p036-graceful-degradation.md)
|
|
124
|
+
- [P038 — Bounded Retry](p038-bounded-retry.md)
|
|
125
|
+
- [P039 — Bounded Waiting](p039-bounded-waiting.md)
|
|
126
|
+
- [P042 — Fault Isolation / Bulkheads](p042-fault-isolation-bulkheads.md)
|
|
127
|
+
|
|
128
|
+
## References
|
|
129
|
+
|
|
130
|
+
### Source information
|
|
131
|
+
|
|
132
|
+
- [Michael T. Nygard, *Release It!*, second edition](https://pragprog.com/titles/mnee2/release-it-second-edition/)
|
|
133
|
+
— a source that made the circuit-breaker pattern known to many production-software engineers.
|
|
134
|
+
- [Martin Fowler, “Circuit Breaker” (2014)](https://martinfowler.com/bliki/CircuitBreaker.html)
|
|
135
|
+
— practitioner information that identifies Nygard as the source and shows the state model.
|
|
136
|
+
|
|
137
|
+
### Applicable information
|
|
138
|
+
|
|
139
|
+
- [Microsoft Azure, Circuit Breaker pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker)
|
|
140
|
+
— applicable guidance for thresholds, open and half-open states, recovery probes, and retry
|
|
141
|
+
interaction.
|
|
142
|
+
|
|
143
|
+
### More information
|
|
144
|
+
|
|
145
|
+
- [Google SRE, Addressing Cascading Failures](https://sre.google/sre-book/addressing-cascading-failures/)
|
|
146
|
+
— context for how continuous calls, timeouts, and retries propagate failure.
|
|
147
|
+
|
|
148
|
+
[Back to the engineering principles catalog](../README.md#p043)
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# P044 — Atomicity Where Possible
|
|
2
|
+
|
|
3
|
+
## Definition
|
|
4
|
+
|
|
5
|
+
When state changes are one logical operation and share a supported transaction boundary, make the
|
|
6
|
+
result all-or-none. All changes commit, or no change commits.
|
|
7
|
+
|
|
8
|
+
If concurrent observers must not see state between steps, select the isolation level or atomic
|
|
9
|
+
publication control independently.
|
|
10
|
+
|
|
11
|
+
**Aliases:** all-or-nothing update, transactional commit, failure atomicity
|
|
12
|
+
|
|
13
|
+
## Provenance
|
|
14
|
+
|
|
15
|
+
**Classification:** established principle.
|
|
16
|
+
|
|
17
|
+
Engineers used atomic transactions before the ACID acronym. Sources connect the ACID terms to a
|
|
18
|
+
1983 paper. Härder and Reuter wrote that paper. It is not the source of all atomic-update types.
|
|
19
|
+
|
|
20
|
+
## Decision rule
|
|
21
|
+
|
|
22
|
+
If only some effects can commit and violate an invariant, use one supported transaction boundary
|
|
23
|
+
for all effects.
|
|
24
|
+
If the boundary cannot contain all effects, use custom reversal or compensation.
|
|
25
|
+
|
|
26
|
+
If visibility of only some effects can violate an invariant, select isolation or atomic publication
|
|
27
|
+
independently.
|
|
28
|
+
|
|
29
|
+
## How to apply
|
|
30
|
+
|
|
31
|
+
- Find the logical operation, applicable state, invariants, and observers.
|
|
32
|
+
- Use supported transaction controls from the data store, file system, message broker, or platform.
|
|
33
|
+
Use an all-or-none commit.
|
|
34
|
+
- Select an isolation level or atomic publication control that satisfies the visibility contract.
|
|
35
|
+
- Limit transaction scope and time. While the transaction holds resources, do not make network
|
|
36
|
+
calls or wait for users.
|
|
37
|
+
- Before the transaction, validate prerequisites. After reversible work, start irreversible
|
|
38
|
+
external effects.
|
|
39
|
+
- If the system does not receive the commit acknowledgment, use a status query to resolve the unknown outcome.
|
|
40
|
+
- Do tests of failures before commit, during commit, and after loss of the commit acknowledgment.
|
|
41
|
+
Do an isolation test with concurrent observation.
|
|
42
|
+
|
|
43
|
+
## Diagram
|
|
44
|
+
|
|
45
|
+
```mermaid
|
|
46
|
+
flowchart TD
|
|
47
|
+
A["Find one logical operation"] --> B{"Can one supported transaction contain all effects?"}
|
|
48
|
+
B -- No --> C["Use durable completed-step data and compensation"]
|
|
49
|
+
B -- Yes --> D["Start the transaction"]
|
|
50
|
+
D --> E["Apply all state changes"]
|
|
51
|
+
E --> F{"Did all changes succeed?"}
|
|
52
|
+
F -- Yes --> G["Commit all changes"]
|
|
53
|
+
F -- No --> H["Abort without a committed change"]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Language examples
|
|
57
|
+
|
|
58
|
+
Each example commits the order, items, and inventory reservation as one transaction.
|
|
59
|
+
|
|
60
|
+
### Python
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
def place_order(db, order, items):
|
|
64
|
+
with db.transaction() as tx:
|
|
65
|
+
tx.insert_order(order)
|
|
66
|
+
tx.insert_items(order.id, items)
|
|
67
|
+
tx.reserve_inventory(items)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Rust
|
|
71
|
+
|
|
72
|
+
```rust
|
|
73
|
+
fn place_order(db: &mut Database, order: &Order, items: &[Item]) -> Result<(), Error> {
|
|
74
|
+
let mut tx = db.transaction()?;
|
|
75
|
+
tx.insert_order(order)?;
|
|
76
|
+
tx.insert_items(order.id, items)?;
|
|
77
|
+
tx.reserve_inventory(items)?;
|
|
78
|
+
tx.commit()
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Boundaries and tensions
|
|
83
|
+
|
|
84
|
+
Atomicity has a specified scope. A database transaction does not include an email,
|
|
85
|
+
remote API, file system, or second data store.
|
|
86
|
+
|
|
87
|
+
If its effects are not in its boundary, do not identify a local transaction as an end-to-end atomic operation.
|
|
88
|
+
|
|
89
|
+
When one supported boundary cannot contain the workflow, apply
|
|
90
|
+
[P045](p045-compensation-where-atomicity-is-impossible.md) and durable completed-step data. Do not make a
|
|
91
|
+
distributed transaction without platform support.
|
|
92
|
+
|
|
93
|
+
[P033](p033-state-safe-failure-semantics.md) gives the failure requirement for all operations.
|
|
94
|
+
Atomicity does not guarantee isolation, durability, or business correctness. Record these guarantees
|
|
95
|
+
independently.
|
|
96
|
+
|
|
97
|
+
## Examples
|
|
98
|
+
|
|
99
|
+
### Positive application
|
|
100
|
+
|
|
101
|
+
A database transaction inserts an order and its line items. It also updates the inventory
|
|
102
|
+
reservation. All changes commit together, or no change commits.
|
|
103
|
+
|
|
104
|
+
Readers with a contract for a stable multi-object view use an isolation level that supplies this view.
|
|
105
|
+
|
|
106
|
+
### Misuse or counterexample
|
|
107
|
+
|
|
108
|
+
Code commits an order and then publishes an event. It identifies the pair as one atomic operation. A failure
|
|
109
|
+
between those steps causes committed state without its necessary event.
|
|
110
|
+
|
|
111
|
+
### Athena or agent workflow
|
|
112
|
+
|
|
113
|
+
An Athena workflow assembles and validates a document before target replacement. It keeps all
|
|
114
|
+
related repository edits in one patch. It records validation failure before external publication.
|
|
115
|
+
|
|
116
|
+
## Related principles
|
|
117
|
+
|
|
118
|
+
- [P033 — State-Safe Failure Semantics](p033-state-safe-failure-semantics.md)
|
|
119
|
+
- [P037 — Idempotency Before Retry](p037-idempotency-before-retry.md)
|
|
120
|
+
- [P045 — Compensation Where Atomicity Is Impossible](p045-compensation-where-atomicity-is-impossible.md)
|
|
121
|
+
- [P083 — Irreversible Actions Last](../README.md#p083)
|
|
122
|
+
|
|
123
|
+
## References
|
|
124
|
+
|
|
125
|
+
### Source information
|
|
126
|
+
|
|
127
|
+
- [Härder and Reuter, “Principles of Transaction-Oriented Database Recovery” (1983)](https://doi.org/10.1145/289.291)
|
|
128
|
+
— a source for the ACID terms and transaction recovery framework.
|
|
129
|
+
|
|
130
|
+
### Applicable information
|
|
131
|
+
|
|
132
|
+
- [PostgreSQL 18, Transactions](https://www.postgresql.org/docs/18/tutorial-transactions.html)
|
|
133
|
+
— database documentation with examples of all-or-none updates, visibility, commit, and
|
|
134
|
+
reversal.
|
|
135
|
+
|
|
136
|
+
### More information
|
|
137
|
+
|
|
138
|
+
- [AWS Builders' Library, Making retries safe with idempotent APIs](https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/)
|
|
139
|
+
— shows when an idempotency token and its related state change must use one atomic operation.
|
|
140
|
+
|
|
141
|
+
[Back to the engineering principles catalog](../README.md#p044)
|