resilient-circuit 0.4.1__py3-none-any.whl
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.
- resilient_circuit/__init__.py +16 -0
- resilient_circuit/backoff.py +37 -0
- resilient_circuit/buffer.py +55 -0
- resilient_circuit/circuit_breaker.py +311 -0
- resilient_circuit/cli.py +261 -0
- resilient_circuit/exceptions.py +10 -0
- resilient_circuit/failsafe.py +34 -0
- resilient_circuit/policy.py +13 -0
- resilient_circuit/py.typed +0 -0
- resilient_circuit/retry.py +47 -0
- resilient_circuit/storage.py +252 -0
- resilient_circuit-0.4.1.dist-info/METADATA +443 -0
- resilient_circuit-0.4.1.dist-info/RECORD +17 -0
- resilient_circuit-0.4.1.dist-info/WHEEL +5 -0
- resilient_circuit-0.4.1.dist-info/entry_points.txt +2 -0
- resilient_circuit-0.4.1.dist-info/licenses/LICENSE +201 -0
- resilient_circuit-0.4.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: resilient-circuit
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: A resilient circuit breaker and retry library with PostgreSQL support for distributed systems
|
|
5
|
+
Author-email: Farshid Ashouri <farsheed.ashouri@gmail.com>
|
|
6
|
+
License: Apache Software License 2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/rodmena-limited/resilient-circuit
|
|
8
|
+
Project-URL: Repository, https://github.com/rodmena-limited/resilient-circuit
|
|
9
|
+
Project-URL: Documentation, https://resilient-circuit.readthedocs.io
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Topic :: System :: Distributed Computing
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
28
|
+
Requires-Dist: isort>=5.0.0; extra == "dev"
|
|
29
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-mock>=3.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
33
|
+
Provides-Extra: postgres
|
|
34
|
+
Requires-Dist: psycopg[binary]>=3.1.0; extra == "postgres"
|
|
35
|
+
Requires-Dist: python-dotenv>=1.0.0; extra == "postgres"
|
|
36
|
+
Provides-Extra: docs
|
|
37
|
+
Requires-Dist: sphinx>=7.0.0; extra == "docs"
|
|
38
|
+
Requires-Dist: sphinx-rtd-theme>=2.0.0; extra == "docs"
|
|
39
|
+
Requires-Dist: sphinx-autodoc-typehints>=1.25.0; extra == "docs"
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
# Resilient Circuit
|
|
43
|
+
|
|
44
|
+
<div align="center">
|
|
45
|
+
|
|
46
|
+
[](https://badge.fury.io/py/resilient-circuit)
|
|
47
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
48
|
+
[](https://pypi.org/project/resilient-circuit/)
|
|
49
|
+
[](https://resilient-circuit.readthedocs.io/)
|
|
50
|
+
|
|
51
|
+
**Part of the Highway Workflow Engine** - A robust resilience library for Python applications
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Overview
|
|
57
|
+
|
|
58
|
+
Resilient Circuit is a powerful resilience library designed to make your Python applications fault-tolerant and highly available. It's an integral component of the Highway Workflow Engine, providing essential failure handling capabilities for modern distributed systems.
|
|
59
|
+
|
|
60
|
+
This library implements the Circuit Breaker and Retry patterns, offering elegant solutions for handling failures in networked systems, external service calls, and unreliable dependencies.
|
|
61
|
+
|
|
62
|
+
For comprehensive documentation, visit our [Read the Docs page](https://resilient-circuit.readthedocs.io/).
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install resilient_circuit
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### PostgreSQL Storage Support (Optional)
|
|
71
|
+
|
|
72
|
+
For shared state across multiple instances, you can use PostgreSQL as the storage backend:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install resilient_circuit[postgres]
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Or install the dependencies separately:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install psycopg[binary] python-dotenv
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Features
|
|
85
|
+
|
|
86
|
+
- **Circuit Breaker Pattern**: Prevents cascading failures in distributed systems
|
|
87
|
+
- **Retry Pattern**: Automatically retries failed operations with configurable backoff
|
|
88
|
+
- **Composable**: Chain multiple policies together for sophisticated error handling
|
|
89
|
+
- **Decorator Support**: Clean, easy-to-read syntax with Python decorators
|
|
90
|
+
- **Fine-grained Control**: Configure failure thresholds, cooldown periods, and backoff strategies
|
|
91
|
+
- **State Monitoring**: Track breaker state and execution history
|
|
92
|
+
- **Shared State Storage**: Optional PostgreSQL backend for distributed applications
|
|
93
|
+
|
|
94
|
+
## Quick Start
|
|
95
|
+
|
|
96
|
+
### Basic Circuit Protector
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
from datetime import timedelta
|
|
100
|
+
from fractions import Fraction
|
|
101
|
+
from resilient_circuit import CircuitProtectorPolicy
|
|
102
|
+
|
|
103
|
+
# Create a circuit protector that trips after 3 failures
|
|
104
|
+
protector = CircuitProtectorPolicy(
|
|
105
|
+
failure_limit=Fraction(3, 10), # 3 out of 10 failures
|
|
106
|
+
cooldown=timedelta(seconds=30) # 30-second cooldown
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
@protector
|
|
110
|
+
def unreliable_service_call():
|
|
111
|
+
# Your potentially failing external service call
|
|
112
|
+
import random
|
|
113
|
+
if random.random() < 0.7:
|
|
114
|
+
raise Exception("Service temporarily unavailable")
|
|
115
|
+
return "Success!"
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Advanced Retry with Exponential Backoff
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from datetime import timedelta
|
|
122
|
+
from resilient_circuit import RetryWithBackoffPolicy, ExponentialDelay
|
|
123
|
+
|
|
124
|
+
# Create an exponential backoff strategy
|
|
125
|
+
backoff = ExponentialDelay(
|
|
126
|
+
min_delay=timedelta(seconds=1),
|
|
127
|
+
max_delay=timedelta(seconds=10),
|
|
128
|
+
factor=2,
|
|
129
|
+
jitter=0.1
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Apply retry policy with backoff
|
|
133
|
+
retry_policy = RetryWithBackoffPolicy(
|
|
134
|
+
max_retries=3,
|
|
135
|
+
backoff=backoff
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
@retry_policy
|
|
139
|
+
def unreliable_database_operation():
|
|
140
|
+
# Operation that might fail temporarily
|
|
141
|
+
import random
|
|
142
|
+
if random.random() < 0.5:
|
|
143
|
+
raise ConnectionError("Database temporarily unavailable")
|
|
144
|
+
return "Database operation completed"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Combining Circuit Protector and Retry
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from resilient_circuit import SafetyNet, CircuitProtectorPolicy, RetryWithBackoffPolicy
|
|
151
|
+
|
|
152
|
+
# Combine both patterns using SafetyNet
|
|
153
|
+
safety_net = SafetyNet(
|
|
154
|
+
policies=(
|
|
155
|
+
RetryWithBackoffPolicy(max_retries=2),
|
|
156
|
+
CircuitProtectorPolicy(failure_limit=Fraction(2, 5))
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
@safety_net
|
|
161
|
+
def resilient_external_api_call():
|
|
162
|
+
# This will first retry, then circuit-protect if needed
|
|
163
|
+
import requests
|
|
164
|
+
response = requests.get("https://external-api.example.com/data")
|
|
165
|
+
return response.json()
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Detailed Examples
|
|
169
|
+
|
|
170
|
+
### Circuit Protector Customization
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from datetime import timedelta
|
|
174
|
+
from fractions import Fraction
|
|
175
|
+
from resilient_circuit import CircuitProtectorPolicy, CircuitState
|
|
176
|
+
|
|
177
|
+
def custom_exception_handler(exc):
|
|
178
|
+
"""Only handle specific exceptions"""
|
|
179
|
+
return isinstance(exc, (ConnectionError, TimeoutError))
|
|
180
|
+
|
|
181
|
+
def status_change_handler(policy, old_status, new_status):
|
|
182
|
+
"""Handle status transitions"""
|
|
183
|
+
print(f"Circuit protector changed status: {old_status.name} -> {new_status.name}")
|
|
184
|
+
|
|
185
|
+
# Fully customized circuit protector
|
|
186
|
+
custom_protector = CircuitProtectorPolicy(
|
|
187
|
+
cooldown=timedelta(minutes=1), # 1-minute cooldown
|
|
188
|
+
failure_limit=Fraction(3, 10), # Trip after 30% failure rate
|
|
189
|
+
success_limit=Fraction(5, 5), # Close after 5 consecutive successes
|
|
190
|
+
should_handle=custom_exception_handler, # Custom exception filter
|
|
191
|
+
on_status_change=status_change_handler # Status change listener
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
@custom_protector
|
|
195
|
+
def monitored_service_call():
|
|
196
|
+
# Your service call with enhanced monitoring
|
|
197
|
+
pass
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Complex Retry Scenarios
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from resilient_circuit import RetryWithBackoffPolicy, FixedDelay
|
|
204
|
+
|
|
205
|
+
# Constant delay between retries
|
|
206
|
+
constant_backoff = FixedDelay(delay=timedelta(seconds=2))
|
|
207
|
+
|
|
208
|
+
retry_with_constant_backoff = RetryWithBackoffPolicy(
|
|
209
|
+
max_retries=5,
|
|
210
|
+
backoff=constant_backoff,
|
|
211
|
+
should_handle=lambda e: isinstance(e, ConnectionError)
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
@retry_with_constant_backoff
|
|
215
|
+
def service_with_constant_retry():
|
|
216
|
+
# This will retry every 2 seconds up to 5 times
|
|
217
|
+
pass
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Accessing Circuit Protector Status
|
|
221
|
+
|
|
222
|
+
```python
|
|
223
|
+
from resilient_circuit import CircuitProtectorPolicy
|
|
224
|
+
|
|
225
|
+
protector = CircuitProtectorPolicy(failure_limit=Fraction(2, 5))
|
|
226
|
+
|
|
227
|
+
@protector
|
|
228
|
+
def service_call():
|
|
229
|
+
pass
|
|
230
|
+
|
|
231
|
+
# Check protector status and execution log
|
|
232
|
+
print(f"Current status: {protector.status.name}")
|
|
233
|
+
print(f"Execution log: {list(protector.execution_log)}")
|
|
234
|
+
|
|
235
|
+
# The execution_log buffer maintains success/failure record
|
|
236
|
+
if protector.status == CircuitState.OPEN:
|
|
237
|
+
print("Circuit protector is currently open - requests are blocked")
|
|
238
|
+
else:
|
|
239
|
+
service_call() # Execute call if not in OPEN status
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## PostgreSQL Shared Storage
|
|
243
|
+
|
|
244
|
+
For distributed applications running across multiple instances, Resilient Circuit supports PostgreSQL as a shared storage backend. This allows circuit breaker state to be synchronized across all instances of your application.
|
|
245
|
+
|
|
246
|
+
### Setting Up PostgreSQL Storage
|
|
247
|
+
|
|
248
|
+
1. **Install PostgreSQL dependencies:**
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
pip install resilient_circuit[postgres]
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
2. **Create the database:**
|
|
255
|
+
|
|
256
|
+
You need to create the database first (the CLI assumes the database exists). Create it using your preferred method:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
createdb -h localhost -p 5432 -U postgres resilient_circuit_db
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Or using psql:
|
|
263
|
+
```sql
|
|
264
|
+
CREATE DATABASE resilient_circuit_db;
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
3. **Configure environment variables:**
|
|
268
|
+
|
|
269
|
+
Create a `.env` file in your project root:
|
|
270
|
+
|
|
271
|
+
```env
|
|
272
|
+
RC_DB_HOST=localhost
|
|
273
|
+
RC_DB_PORT=5432
|
|
274
|
+
RC_DB_NAME=resilient_circuit_db
|
|
275
|
+
RC_DB_USER=postgres
|
|
276
|
+
RC_DB_PASSWORD=your_password
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
4. **Use the CLI to set up the table:**
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
resilient-circuit-cli pg-setup
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
This command will read the database configuration from your environment variables and create the necessary table and indexes.
|
|
286
|
+
|
|
287
|
+
You can also use additional options:
|
|
288
|
+
- `--yes` to skip the confirmation prompt
|
|
289
|
+
- `--dry-run` to see what would be done without making changes
|
|
290
|
+
|
|
291
|
+
Example:
|
|
292
|
+
```bash
|
|
293
|
+
resilient-circuit-cli pg-setup --yes # Skip confirmation
|
|
294
|
+
resilient-circuit-cli pg-setup --dry-run # Show what would be done
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### Using PostgreSQL Storage
|
|
298
|
+
|
|
299
|
+
Once configured, the circuit breaker will automatically use PostgreSQL storage when environment variables are present:
|
|
300
|
+
|
|
301
|
+
```python
|
|
302
|
+
from datetime import timedelta
|
|
303
|
+
from fractions import Fraction
|
|
304
|
+
from resilient_circuit import CircuitProtectorPolicy
|
|
305
|
+
|
|
306
|
+
# This will automatically use PostgreSQL if RC_DB_* env vars are set
|
|
307
|
+
circuit_breaker = CircuitProtectorPolicy(
|
|
308
|
+
resource_key="payment_service",
|
|
309
|
+
cooldown=timedelta(seconds=60),
|
|
310
|
+
failure_limit=Fraction(5, 10), # 50% failure rate
|
|
311
|
+
success_limit=Fraction(3, 3) # 3 consecutive successes to close
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
@circuit_breaker
|
|
315
|
+
def process_payment():
|
|
316
|
+
# Your payment processing logic
|
|
317
|
+
pass
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Benefits of PostgreSQL Storage
|
|
321
|
+
|
|
322
|
+
- **Shared State**: Circuit breaker state is synchronized across all application instances
|
|
323
|
+
- **Persistence**: State survives application restarts
|
|
324
|
+
- **Monitoring**: Query circuit breaker state directly from the database
|
|
325
|
+
- **Scalability**: Supports high-concurrency applications
|
|
326
|
+
- **Atomic Operations**: Uses PostgreSQL row-level locking for thread-safe updates
|
|
327
|
+
|
|
328
|
+
### Monitoring Circuit Breakers
|
|
329
|
+
|
|
330
|
+
Query the database to monitor circuit breaker status:
|
|
331
|
+
|
|
332
|
+
```sql
|
|
333
|
+
-- View all circuit breakers and their status
|
|
334
|
+
SELECT resource_key, state, failure_count, open_until, updated_at
|
|
335
|
+
FROM rc_circuit_breakers
|
|
336
|
+
ORDER BY updated_at DESC;
|
|
337
|
+
|
|
338
|
+
-- Find all open circuit breakers
|
|
339
|
+
SELECT resource_key, open_until
|
|
340
|
+
FROM rc_circuit_breakers
|
|
341
|
+
WHERE state = 'OPEN';
|
|
342
|
+
|
|
343
|
+
-- Check failure rates for specific services
|
|
344
|
+
SELECT resource_key, failure_count
|
|
345
|
+
FROM rc_circuit_breakers
|
|
346
|
+
WHERE state = 'CLOSED';
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Fallback to In-Memory Storage
|
|
350
|
+
|
|
351
|
+
If PostgreSQL is not configured or unavailable, the circuit breaker automatically falls back to in-memory storage:
|
|
352
|
+
|
|
353
|
+
```python
|
|
354
|
+
# No environment variables set - uses in-memory storage
|
|
355
|
+
circuit_breaker = CircuitProtectorPolicy(resource_key="my_service")
|
|
356
|
+
|
|
357
|
+
# Or explicitly specify in-memory storage
|
|
358
|
+
from resilient_circuit.storage import InMemoryStorage
|
|
359
|
+
|
|
360
|
+
circuit_breaker = CircuitProtectorPolicy(
|
|
361
|
+
resource_key="my_service",
|
|
362
|
+
storage=InMemoryStorage()
|
|
363
|
+
)
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Environment Variables Reference
|
|
367
|
+
|
|
368
|
+
| Variable | Description | Default |
|
|
369
|
+
|----------|-------------|---------|
|
|
370
|
+
| `RC_DB_HOST` | PostgreSQL host | Required |
|
|
371
|
+
| `RC_DB_PORT` | PostgreSQL port | `5432` |
|
|
372
|
+
| `RC_DB_NAME` | Database name | `resilient_circuit_db` |
|
|
373
|
+
| `RC_DB_USER` | Database user | `postgres` |
|
|
374
|
+
| `RC_DB_PASSWORD` | Database password | Required |
|
|
375
|
+
|
|
376
|
+
## Highway Workflow Engine Integration
|
|
377
|
+
|
|
378
|
+
Resilient Circuit is a core component of the Highway Workflow Engine, designed for building resilient, distributed applications. The Highway Workflow Engine provides:
|
|
379
|
+
|
|
380
|
+
- **Workflow Orchestration**: Define complex business processes
|
|
381
|
+
- **Task Management**: Execute and monitor long-running tasks
|
|
382
|
+
- **Resilience Patterns**: Built-in fault tolerance with circuit breakers and retries
|
|
383
|
+
- **Monitoring & Observability**: Track workflow execution and identify bottlenecks
|
|
384
|
+
|
|
385
|
+
Learn more about the complete Highway Workflow Engine at [highway-workflow-engine.readthedocs.io](https://highway-workflow-engine.readthedocs.io).
|
|
386
|
+
|
|
387
|
+
## API Reference
|
|
388
|
+
|
|
389
|
+
### CircuitProtectorPolicy
|
|
390
|
+
|
|
391
|
+
Implements the circuit protector pattern with three statuses: CLOSED, OPEN, HALF_OPEN.
|
|
392
|
+
|
|
393
|
+
**Parameters:**
|
|
394
|
+
- `cooldown` (timedelta): Duration before transitioning from OPEN to HALF_OPEN
|
|
395
|
+
- `failure_limit` (Fraction): Failure rate to trip the protector (e.g., Fraction(3, 10) for 3 out of 10)
|
|
396
|
+
- `success_limit` (Fraction): Success rate to close the protector in HALF_OPEN status
|
|
397
|
+
- `should_handle` (Callable): Predicate to determine which exceptions to count as failures
|
|
398
|
+
- `on_status_change` (Callable): Callback when the protector changes status
|
|
399
|
+
|
|
400
|
+
### RetryWithBackoffPolicy
|
|
401
|
+
|
|
402
|
+
Implements the retry pattern with configurable backoff strategies.
|
|
403
|
+
|
|
404
|
+
**Parameters:**
|
|
405
|
+
- `backoff` (ExponentialDelay | FixedDelay): Backoff strategy between retries
|
|
406
|
+
- `max_retries` (int): Maximum number of retry attempts
|
|
407
|
+
- `should_handle` (Callable): Predicate to determine which exceptions to retry
|
|
408
|
+
|
|
409
|
+
### SafetyNet
|
|
410
|
+
|
|
411
|
+
Combines multiple policies for comprehensive error handling.
|
|
412
|
+
|
|
413
|
+
**Parameters:**
|
|
414
|
+
- `policies` (tuple): Tuple of policies to apply
|
|
415
|
+
|
|
416
|
+
### ExponentialDelay Strategies
|
|
417
|
+
|
|
418
|
+
- `ExponentialDelay`: Exponential backoff with configurable parameters
|
|
419
|
+
- `FixedDelay`: Constant delay between attempts
|
|
420
|
+
|
|
421
|
+
## Best Practices
|
|
422
|
+
|
|
423
|
+
1. **Configure Appropriate Limits**: Set failure limits based on your service's expected error rate
|
|
424
|
+
2. **Use Meaningful Cooldown Periods**: Balance between detecting recovery and avoiding thrashing
|
|
425
|
+
3. **Handle Specific Exceptions**: Use the `should_handle` parameter to only respond to expected failures
|
|
426
|
+
4. **Monitor Status Changes**: Use `on_status_change` to detect and log circuit protector transitions
|
|
427
|
+
5. **Chain Policies Thoughtfully**: Apply retry before circuit protector for optimal resilience
|
|
428
|
+
|
|
429
|
+
## Contributing
|
|
430
|
+
|
|
431
|
+
We welcome contributions to Resilient Circuit! See our [contributing guide](CONTRIBUTING.md) for details.
|
|
432
|
+
|
|
433
|
+
## License
|
|
434
|
+
|
|
435
|
+
Distributed under the Apache Software License 2.0. See [LICENSE](LICENSE) for more information.
|
|
436
|
+
|
|
437
|
+
## Support
|
|
438
|
+
|
|
439
|
+
Need help? Check out our documentation or open an issue on GitHub.
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
*Part of the Highway Workflow Engine family of resilience tools*
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
resilient_circuit/__init__.py,sha256=Z3WOzwCT5fP0VptBNu-bkrbKGGljaDB9QL9FwkcBpQI,552
|
|
2
|
+
resilient_circuit/backoff.py,sha256=aLSFYqU_CROrkDaepZaTF_vUy05fBvRhUruXe3Wcmlk,1148
|
|
3
|
+
resilient_circuit/buffer.py,sha256=UIOxPgo07TmveTbaSSJXHzDZwu_aYRVkgIWbGuMhH-8,1385
|
|
4
|
+
resilient_circuit/circuit_breaker.py,sha256=RwQu490pBulAk5Fl4Kn3URsfrEHqwXqVGa3WxSZuwHc,12190
|
|
5
|
+
resilient_circuit/cli.py,sha256=fQpoajQWO-KOpxjVcRsw_oPtXXPw8mfid4pqFwHmRkw,9563
|
|
6
|
+
resilient_circuit/exceptions.py,sha256=f1A9hK1y9kxOFtzldIMCOy0Ui9cKnLuCkUzPUU7zyR4,162
|
|
7
|
+
resilient_circuit/failsafe.py,sha256=B6piP5gWAn88maJnk_Gp3nSRp0FCCtZ4Lnd7Ekrgo-M,1068
|
|
8
|
+
resilient_circuit/policy.py,sha256=MJeETZKw_oMrRkgfq160nrFrSm6tv1N2pgkGxsaQmRs,289
|
|
9
|
+
resilient_circuit/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
resilient_circuit/retry.py,sha256=I0QWkhXlEj3Pn6yMbTgT70XPM99Rr3wEoIWL6ThaLCY,1476
|
|
11
|
+
resilient_circuit/storage.py,sha256=PI31JdWT11H7Sxc8YrwSth351bWPT_ZfdzTGuhZ78E8,10874
|
|
12
|
+
resilient_circuit-0.4.1.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
|
13
|
+
resilient_circuit-0.4.1.dist-info/METADATA,sha256=PmpXbOfalK3TjPz6LEDbapvtRgealXZhtRskcl8AKec,14761
|
|
14
|
+
resilient_circuit-0.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
15
|
+
resilient_circuit-0.4.1.dist-info/entry_points.txt,sha256=JbXU75gDeU3PsVykHG7Bq1lYJG7hr5KG-3ny-HGCcZI,65
|
|
16
|
+
resilient_circuit-0.4.1.dist-info/top_level.txt,sha256=SFJWwSDlbsmTWV8F67fdmfAK_dtTT9c8L-kfdnior4s,18
|
|
17
|
+
resilient_circuit-0.4.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
resilient_circuit
|