Repository navigation
Commit 976fc49
authored
feat: per-endpoint circuit breaker option (#22)
* feat: per-endpoint circuit breaker option
Add `per_endpoint_circuit_breaker: bool = False` to `HyperpingClient` and
`AsyncHyperpingClient`. When enabled, the client maintains an independent
`CircuitBreaker` per request path (query string and fragment stripped from
the key) so a single flaky endpoint no longer blocks traffic to healthy
ones. Default `False` preserves the original single-shared-breaker
behaviour and all existing breaker tests.
Per-path state is queryable via `client.circuit_breaker_state_for(path)`;
the existing `client.circuit_breaker` property still returns the shared
breaker. The per-path dict is protected by its own `threading.Lock`; the
per-path `CircuitBreaker` instances retain their own internal lock.
Tests cover: isolation between paths, state-query API, query-string
stripping, default-mode unchanged, async parity, and 50-thread concurrent
access.
* refactor: bucket per-endpoint breakers by Endpoint prefix
Address review feedback on the initial per-endpoint breaker implementation.
The previous version keyed the breaker dict on the literal request path. For
paths that embed resource UUIDs (`/v1/monitors/{uuid}`, etc.) this meant
every resource ended up with its own breaker, the dict could grow unbounded
in long-lived clients, and the README's `circuit_breaker_state_for(Endpoint.MONITORS)`
example only saw list-call state, not per-resource calls.
Changes:
- Default breaker key now collapses sub-resource paths under their matching
`Endpoint` prefix (`/v1/monitors`, `/v3/incidents`, ...). The breaker set is
bounded by the number of Endpoint values, not by resource cardinality.
- New `breaker_key_fn: Callable[[str], str] | None` lets callers opt into a
different scheme (per-UUID, per-verb, etc.) and explicitly own bounding.
- OPEN-state error message in per-endpoint mode now includes the breaker key
("Circuit breaker OPEN for '/v1/monitors' - ..."), so the failure points at
which endpoint tripped.
- `circuit_breaker_state_for(path)` now falls back to the shared breaker's
state in default mode instead of raising, so the call is always safe to
make and toggling the flag at construction time doesn't change the API
surface callers see.
- `_breaker_key` rewritten with `urllib.parse.urlsplit` and the dict-lock
comment explains the `threading.Lock` choice for the async client.
Tests added for endpoint canonicalisation, custom `breaker_key_fn`, default-
mode `circuit_breaker_state_for` returning shared state, and the OPEN error
message including the endpoint key.1 parent 03d4940 commit 976fc49
6 files changed
Lines changed: 632 additions & 28 deletions
File tree
- src/hyperping
- tests/unit
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
46 | 46 | | |
47 | 47 | | |
48 | 48 | | |
49 | | - | |
| 49 | + | |
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| |||
106 | 106 | | |
107 | 107 | | |
108 | 108 | | |
109 | | - | |
| 109 | + | |
110 | 110 | | |
111 | 111 | | |
112 | 112 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
8 | 22 | | |
9 | 23 | | |
10 | 24 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
252 | 252 | | |
253 | 253 | | |
254 | 254 | | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
255 | 297 | | |
256 | 298 | | |
257 | 299 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
| 18 | + | |
17 | 19 | | |
| 20 | + | |
18 | 21 | | |
19 | 22 | | |
20 | 23 | | |
| |||
28 | 31 | | |
29 | 32 | | |
30 | 33 | | |
| 34 | + | |
31 | 35 | | |
32 | 36 | | |
33 | 37 | | |
34 | | - | |
| 38 | + | |
35 | 39 | | |
36 | 40 | | |
37 | 41 | | |
| |||
73 | 77 | | |
74 | 78 | | |
75 | 79 | | |
| 80 | + | |
| 81 | + | |
76 | 82 | | |
77 | 83 | | |
78 | 84 | | |
| |||
82 | 88 | | |
83 | 89 | | |
84 | 90 | | |
85 | | - | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
86 | 94 | | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
87 | 104 | | |
88 | 105 | | |
89 | 106 | | |
| |||
92 | 109 | | |
93 | 110 | | |
94 | 111 | | |
| 112 | + | |
95 | 113 | | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
96 | 118 | | |
97 | 119 | | |
98 | 120 | | |
| |||
120 | 142 | | |
121 | 143 | | |
122 | 144 | | |
123 | | - | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
124 | 151 | | |
125 | 152 | | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
126 | 213 | | |
127 | 214 | | |
128 | 215 | | |
| |||
236 | 323 | | |
237 | 324 | | |
238 | 325 | | |
239 | | - | |
| 326 | + | |
240 | 327 | | |
241 | 328 | | |
242 | 329 | | |
| |||
262 | 349 | | |
263 | 350 | | |
264 | 351 | | |
265 | | - | |
266 | | - | |
267 | | - | |
268 | | - | |
269 | | - | |
270 | | - | |
271 | | - | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
272 | 355 | | |
273 | 356 | | |
274 | 357 | | |
| |||
299 | 382 | | |
300 | 383 | | |
301 | 384 | | |
302 | | - | |
| 385 | + | |
303 | 386 | | |
304 | 387 | | |
305 | 388 | | |
| |||
320 | 403 | | |
321 | 404 | | |
322 | 405 | | |
323 | | - | |
| 406 | + | |
324 | 407 | | |
325 | 408 | | |
326 | 409 | | |
| |||
0 commit comments