|
30 | 30 | > There are three states: |
31 | 31 | > - **Closed** — everything is normal, requests go through |
32 | 32 | > - **Open** — failures exceeded the threshold, requests are blocked |
33 | | -> - **Half-Open** — a trial period, one request is allowed through to test recovery |
| 33 | +> - **Half-Open** — a trial period, one request is allowed to test recovery |
34 | 34 |
|
35 | 35 | > "This pattern was popularized by Michael Nygard in his 2007 book *Release It!*. |
36 | 36 | > and Martin Fowler wrote a well-known article about it on his website. If you want to go deeper on the concept, Fowler's article is a great starting point — I'll link it in the description. |
@@ -63,13 +63,13 @@ $ganesha = Ackintosh\Ganesha\Builder::withCountStrategy() |
63 | 63 | ->build(); |
64 | 64 | ``` |
65 | 65 |
|
66 | | -> "All right, let me walk through the options: |
| 66 | +> All right, the adapter is how Ganesha persists its state. Here I'm using Redis. Ganesha supports multiple storage adapters — Redis and Memcached are the ones I'd recommend." |
| 67 | +
|
| 68 | +> "let me walk through the options: |
67 | 69 | > |
68 | 70 | > - `failureCountThreshold(3)` — the circuit trips after 3 consecutive failures |
69 | 71 | > - `intervalToHalfOpen(10)` — 10 seconds after tripping, Ganesha allows one trial request through |
70 | 72 | > |
71 | | -> Cool. The adapter is how Ganesha persists its state. Here I'm using Redis. Ganesha supports multiple storage adapters — Redis and Memcached are the ones I'd recommend." |
72 | | -
|
73 | 73 | --- |
74 | 74 |
|
75 | 75 | ## Scene 3 — The basic API: `isAvailable()`, `success()`, `failure()` |
@@ -130,46 +130,52 @@ var_dump($ganesha->isAvailable($service)); // bool(false) |
130 | 130 |
|
131 | 131 | ```php |
132 | 132 | $ganesha->subscribe(function (string $event, string $service, string $message): void { |
133 | | - error_log(sprintf('[Ganesha] %s: %s', $event, $service)); |
| 133 | + echo sprintf('%s(%s): %s', $event, $service); |
134 | 134 | }); |
135 | 135 | ``` |
136 | 136 |
|
137 | | -> "There are three events: |
138 | | -> - `EVENT_TRIPPED` — the circuit just opened |
139 | | -> - `EVENT_CALMED_DOWN` — the circuit recovered and closed again |
140 | | -> - `EVENT_STORAGE_ERROR` — the storage backend had a problem |
141 | | -> |
142 | | -> Cool. And notice that storage errors are handled gracefully — if Redis goes down, Ganesha defaults to returning `true` from `isAvailable()` rather than crashing your application. It fails open, which is usually the right default for a circuit breaker." |
| 137 | +> It's a good idea to use different log levels depending on the event type |
| 138 | +
|
| 139 | +```php |
| 140 | +$ganesha->subscribe(function (string $event, string $service, string $message): void { |
| 141 | + switch ($event) { |
| 142 | + case \Ackintosh\Ganesha::EVENT_TRIPPED: |
| 143 | + echo sprintf('[ERROR] the circuit just opened %s(%s): %s', $event, $service, $message); |
| 144 | + case \Ackintosh\Ganesha::EVENT_CALMED_DOWN: |
| 145 | + echo sprintf('[INFO] the circuit recovered and closed again %s(%s): %s', $event, $service, $message); |
| 146 | + case \Ackintosh\Ganesha::EVENT_STORAGE_ERROR: |
| 147 | + echo sprintf('[WARN] the storage backend had a problem %s(%s): %s', $event, $service, $message); |
| 148 | + default: |
| 149 | + break; |
| 150 | + } |
| 151 | +}); |
| 152 | +``` |
| 153 | + |
| 154 | +> "All right, let's run it again and confirm that the logs are output as expected." |
143 | 155 |
|
144 | 156 | --- |
145 | 157 |
|
146 | 158 | ## Scene 6 — Brief mention of the Rate Strategy |
147 | 159 |
|
148 | | -> "Okay, I mentioned there's a second strategy — the **Rate strategy**. Instead of counting raw failures, it tracks the failure rate as a percentage over a sliding time window. This is better for high-traffic services where a fixed count doesn't scale well. |
| 160 | +> "All right, let me add a quick note about the strategy. |
149 | 161 |
|
150 | | -```php |
151 | | -$ganesha = Ackintosh\Ganesha\Builder::withRateStrategy() |
152 | | - ->adapter(new Ackintosh\Ganesha\Storage\Adapter\Redis($redis)) |
153 | | - ->failureRateThreshold(50) // trip if 50% of requests fail |
154 | | - ->minimumRequests(10) // but only after at least 10 requests |
155 | | - ->timeWindow(30) // measured over a 30-second window |
156 | | - ->intervalToHalfOpen(10) |
157 | | - ->build(); |
158 | | -``` |
| 162 | +*Open the README, navigate to the Rate strategy.* |
| 163 | + |
| 164 | +> I mentioned there's a second strategy — the **Rate strategy**. Instead of counting failures, it tracks the failure rate as a percentage over a sliding time window. This is better for high-traffic services where a fixed count doesn't scale. |
159 | 165 |
|
160 | 166 | > "All right. We won't go deeper into this today, but the API is identical — same three methods, same event system. Cool." |
161 | 167 |
|
162 | 168 | --- |
163 | 169 |
|
164 | 170 | ## Scene 7 — Tease for Episode 2 |
165 | 171 |
|
166 | | -*Open [src/Ganesha/Storage/Adapter/Redis.php](../src/Ganesha/Storage/Adapter/Redis.php), navigate to the `reset()` method.* |
167 | | - |
168 | 172 | > "All right, before I wrap up — let me show you something I found in the codebase." |
169 | 173 |
|
| 174 | +*Open [src/Ganesha/Storage/Adapter/Redis.php](../src/Ganesha/Storage/Adapter/Redis.php), navigate to the `reset()` method.* |
| 175 | + |
170 | 176 | *Scroll to the `reset()` method's TODO comment.* |
171 | 177 |
|
172 | | -> "There's a TODO here. The `reset()` method — which is supposed to clear all circuit breaker state — is not implemented for the Redis adapter. If you call `$ganesha->reset()` right now with Redis, nothing happens. All right. |
| 178 | +> "There's a TODO here. The `reset()` method — which is supposed to clear all circuit breaker state — is not implemented for the Redis adapter. If you call `$ganesha->reset()` right now with Redis, nothing happens. |
173 | 179 | > |
174 | 180 | > So in the next video, I'm going to fix this. We'll look at how Redis is storing Ganesha's data, figure out the right approach to delete it all safely, write the implementation, and test it. |
175 | 181 | > |
|
0 commit comments