0
# Storage Backends
1
2
PyBreaker supports different storage backends for persisting circuit breaker state. This enables circuit breakers to maintain state across application restarts and coordinate state in distributed systems.
3
4
## Capabilities
5
6
### Memory Storage
7
8
In-memory storage for single-process applications where circuit state doesn't need to persist across restarts.
9
10
```python { .api }
11
class CircuitMemoryStorage:
12
def __init__(self, state: str):
13
"""
14
Create a new in-memory storage instance.
15
16
Args:
17
state (str): Initial circuit state ('open', 'closed', 'half-open')
18
"""
19
20
@property
21
def state(self) -> str:
22
"""Current circuit breaker state."""
23
24
@state.setter
25
def state(self, state: str) -> None:
26
"""Set the current circuit breaker state."""
27
28
@property
29
def counter(self) -> int:
30
"""Current failure counter value."""
31
32
@property
33
def success_counter(self) -> int:
34
"""Current success counter value."""
35
36
@property
37
def opened_at(self) -> datetime | None:
38
"""Datetime when circuit was last opened."""
39
40
@opened_at.setter
41
def opened_at(self, datetime: datetime) -> None:
42
"""Set when circuit was opened."""
43
44
def increment_counter(self) -> None:
45
"""Increment the failure counter by one."""
46
47
def reset_counter(self) -> None:
48
"""Reset the failure counter to zero."""
49
50
def increment_success_counter(self) -> None:
51
"""Increment the success counter by one."""
52
53
def reset_success_counter(self) -> None:
54
"""Reset the success counter to zero."""
55
```
56
57
### Redis Storage
58
59
Redis-backed storage for distributed applications where circuit state needs to be shared across multiple processes or servers.
60
61
```python { .api }
62
class CircuitRedisStorage:
63
def __init__(self,
64
state: str,
65
redis_object: Redis,
66
namespace: str | None = None,
67
fallback_circuit_state: str = "closed",
68
cluster_mode: bool = False):
69
"""
70
Create a new Redis storage instance.
71
72
Args:
73
state (str): Initial circuit state
74
redis_object (Redis): Redis client instance (e.g., redis.Redis())
75
namespace (str | None): Optional namespace for Redis keys
76
fallback_circuit_state (str): State to use when Redis is unavailable
77
cluster_mode (bool): Enable Redis cluster mode support
78
79
Note:
80
Requires 'redis' package to be installed.
81
Do not use decode_responses=True in Redis client.
82
Check pybreaker.HAS_REDIS_SUPPORT to verify availability.
83
"""
84
85
@property
86
def state(self) -> str:
87
"""
88
Current circuit breaker state from Redis.
89
Falls back to fallback_circuit_state on Redis errors.
90
"""
91
92
@state.setter
93
def state(self, state: str) -> None:
94
"""Set the current circuit breaker state in Redis."""
95
96
@property
97
def counter(self) -> int:
98
"""Current failure counter value from Redis."""
99
100
@property
101
def success_counter(self) -> int:
102
"""Current success counter value from Redis."""
103
104
@property
105
def opened_at(self) -> datetime | None:
106
"""Datetime when circuit was last opened, from Redis."""
107
108
@opened_at.setter
109
def opened_at(self, datetime: datetime) -> None:
110
"""Atomically set when circuit was opened in Redis."""
111
112
def increment_counter(self) -> None:
113
"""Increment the failure counter in Redis."""
114
115
def reset_counter(self) -> None:
116
"""Reset the failure counter to zero in Redis."""
117
118
def increment_success_counter(self) -> None:
119
"""Increment the success counter in Redis."""
120
121
def reset_success_counter(self) -> None:
122
"""Reset the success counter to zero in Redis."""
123
```
124
125
### Storage Base Class
126
127
Abstract base class defining the storage interface for custom storage implementations. All concrete storage classes must inherit from this class and implement the abstract methods.
128
129
```python { .api }
130
class CircuitBreakerStorage:
131
def __init__(self, name: str) -> None:
132
"""
133
Create a new storage instance.
134
135
Args:
136
name (str): Human-friendly name for this storage type
137
"""
138
139
@property
140
def name(self) -> str:
141
"""Human friendly name that identifies this storage type."""
142
143
@property
144
def state(self) -> str:
145
"""Override this method to retrieve the current circuit breaker state."""
146
147
@state.setter
148
def state(self, state: str) -> None:
149
"""Override this method to set the current circuit breaker state."""
150
151
def increment_counter(self) -> None:
152
"""Override this method to increase the failure counter by one."""
153
154
def reset_counter(self) -> None:
155
"""Override this method to set the failure counter to zero."""
156
157
def increment_success_counter(self) -> None:
158
"""Override this method to increase the success counter by one."""
159
160
def reset_success_counter(self) -> None:
161
"""Override this method to set the success counter to zero."""
162
163
@property
164
def counter(self) -> int:
165
"""Override this method to retrieve the current failure counter value."""
166
167
@property
168
def success_counter(self) -> int:
169
"""Override this method to retrieve the current success counter value."""
170
171
@property
172
def opened_at(self) -> datetime | None:
173
"""Override this method to retrieve when the circuit was opened."""
174
175
@opened_at.setter
176
def opened_at(self, datetime: datetime) -> None:
177
"""Override this method to set when the circuit was opened."""
178
```
179
180
## Usage Examples
181
182
### Memory Storage (Default)
183
184
```python
185
import pybreaker
186
187
# Memory storage is used by default
188
breaker = pybreaker.CircuitBreaker(fail_max=5, reset_timeout=60)
189
190
# Explicitly specify memory storage
191
storage = pybreaker.CircuitMemoryStorage(state=pybreaker.STATE_CLOSED)
192
breaker = pybreaker.CircuitBreaker(state_storage=storage)
193
```
194
195
### Redis Storage for Distributed Systems
196
197
```python
198
import pybreaker
199
import redis
200
201
# Create Redis client
202
redis_client = redis.Redis(host='localhost', port=6379, db=0)
203
204
# Create Redis storage
205
storage = pybreaker.CircuitRedisStorage(
206
state=pybreaker.STATE_CLOSED,
207
redis_object=redis_client,
208
namespace="myapp", # Optional namespace for keys
209
fallback_circuit_state=pybreaker.STATE_CLOSED
210
)
211
212
# Create circuit breaker with Redis storage
213
breaker = pybreaker.CircuitBreaker(
214
fail_max=5,
215
reset_timeout=60,
216
state_storage=storage,
217
name="user_service"
218
)
219
```
220
221
### Redis Storage with Django
222
223
```python
224
import pybreaker
225
from django_redis import get_redis_connection
226
227
# Use existing Django Redis connection
228
redis_client = get_redis_connection('default')
229
230
storage = pybreaker.CircuitRedisStorage(
231
state=pybreaker.STATE_CLOSED,
232
redis_object=redis_client,
233
namespace="circuit_breakers"
234
)
235
236
breaker = pybreaker.CircuitBreaker(state_storage=storage)
237
```
238
239
### Multiple Circuit Breakers with Redis
240
241
```python
242
import pybreaker
243
import redis
244
245
redis_client = redis.Redis(host='localhost', port=6379, db=0)
246
247
# Each service gets its own namespace
248
user_storage = pybreaker.CircuitRedisStorage(
249
state=pybreaker.STATE_CLOSED,
250
redis_object=redis_client,
251
namespace="user_service"
252
)
253
254
payment_storage = pybreaker.CircuitRedisStorage(
255
state=pybreaker.STATE_CLOSED,
256
redis_object=redis_client,
257
namespace="payment_service"
258
)
259
260
user_breaker = pybreaker.CircuitBreaker(state_storage=user_storage)
261
payment_breaker = pybreaker.CircuitBreaker(state_storage=payment_storage)
262
```
263
264
### Redis Cluster Mode
265
266
```python
267
import pybreaker
268
import redis
269
270
# For Redis cluster deployments
271
redis_client = redis.Redis(host='cluster-endpoint', port=6379)
272
273
storage = pybreaker.CircuitRedisStorage(
274
state=pybreaker.STATE_CLOSED,
275
redis_object=redis_client,
276
cluster_mode=True # Enable cluster mode
277
)
278
279
breaker = pybreaker.CircuitBreaker(state_storage=storage)
280
```
281
282
### Custom Storage Implementation
283
284
```python
285
import pybreaker
286
import sqlite3
287
from datetime import datetime
288
289
class SQLiteStorage(pybreaker.CircuitBreakerStorage):
290
def __init__(self, db_path, circuit_name):
291
super().__init__("sqlite")
292
self.db_path = db_path
293
self.circuit_name = circuit_name
294
self._init_db()
295
296
def _init_db(self):
297
# Initialize SQLite database and tables
298
pass
299
300
@property
301
def state(self):
302
# Implement state retrieval from SQLite
303
pass
304
305
@state.setter
306
def state(self, state):
307
# Implement state storage to SQLite
308
pass
309
310
# Implement other required methods...
311
312
# Use custom storage
313
storage = SQLiteStorage("/path/to/circuit.db", "user_service")
314
breaker = pybreaker.CircuitBreaker(state_storage=storage)
315
```