queuelens 0.1.0__tar.gz
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.
- queuelens-0.1.0/.github/workflows/publish.yml +73 -0
- queuelens-0.1.0/.gitignore +18 -0
- queuelens-0.1.0/DELIVERY.md +187 -0
- queuelens-0.1.0/LICENSE +21 -0
- queuelens-0.1.0/PKG-INFO +258 -0
- queuelens-0.1.0/README.md +242 -0
- queuelens-0.1.0/pyproject.toml +41 -0
- queuelens-0.1.0/queuelens/__init__.py +5 -0
- queuelens-0.1.0/queuelens/client.py +91 -0
- queuelens-0.1.0/queuelens/config.py +100 -0
- queuelens-0.1.0/queuelens/events.py +46 -0
- queuelens-0.1.0/queuelens/exceptions.py +6 -0
- queuelens-0.1.0/queuelens/instrumentation/__init__.py +3 -0
- queuelens-0.1.0/queuelens/instrumentation/celery.py +546 -0
- queuelens-0.1.0/queuelens/transport/__init__.py +0 -0
- queuelens-0.1.0/queuelens/transport/buffer.py +56 -0
- queuelens-0.1.0/queuelens/transport/flusher.py +167 -0
- queuelens-0.1.0/queuelens/transport/sender.py +83 -0
- queuelens-0.1.0/sdk_tests/__init__.py +0 -0
- queuelens-0.1.0/sdk_tests/test_buffer.py +161 -0
- queuelens-0.1.0/sdk_tests/test_celery_instrumentation.py +417 -0
- queuelens-0.1.0/sdk_tests/test_client.py +154 -0
- queuelens-0.1.0/sdk_tests/test_config.py +107 -0
- queuelens-0.1.0/sdk_tests/test_events.py +96 -0
- queuelens-0.1.0/sdk_tests/test_flusher.py +339 -0
- queuelens-0.1.0/sdk_tests/test_sender.py +273 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
|
|
2
|
+
name: Publish QLens SDK to PyPI
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
tags:
|
|
7
|
+
- "v*"
|
|
8
|
+
|
|
9
|
+
# Allows us to test the build without publishing.
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
build:
|
|
17
|
+
name: Build SDK distributions
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout repository
|
|
22
|
+
uses: actions/checkout@v6
|
|
23
|
+
with:
|
|
24
|
+
persist-credentials: false
|
|
25
|
+
|
|
26
|
+
- name: Set up Python
|
|
27
|
+
uses: actions/setup-python@v6
|
|
28
|
+
with:
|
|
29
|
+
python-version: "3.12"
|
|
30
|
+
|
|
31
|
+
- name: Install build dependencies
|
|
32
|
+
run: |
|
|
33
|
+
python -m pip install --upgrade build twine
|
|
34
|
+
|
|
35
|
+
- name: Build distributions
|
|
36
|
+
run: |
|
|
37
|
+
python -m build
|
|
38
|
+
|
|
39
|
+
- name: Validate distributions
|
|
40
|
+
run: |
|
|
41
|
+
python -m twine check dist/*
|
|
42
|
+
|
|
43
|
+
- name: Upload distributions
|
|
44
|
+
uses: actions/upload-artifact@v6
|
|
45
|
+
with:
|
|
46
|
+
name: python-package-distributions
|
|
47
|
+
path: dist/
|
|
48
|
+
if-no-files-found: error
|
|
49
|
+
|
|
50
|
+
publish:
|
|
51
|
+
name: Publish to PyPI
|
|
52
|
+
needs: build
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
|
|
55
|
+
# Only publish when a version tag is pushed.
|
|
56
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
57
|
+
|
|
58
|
+
environment:
|
|
59
|
+
name: pypi
|
|
60
|
+
url: https://pypi.org/p/queuelens
|
|
61
|
+
|
|
62
|
+
permissions:
|
|
63
|
+
id-token: write
|
|
64
|
+
|
|
65
|
+
steps:
|
|
66
|
+
- name: Download distributions
|
|
67
|
+
uses: actions/download-artifact@v6
|
|
68
|
+
with:
|
|
69
|
+
name: python-package-distributions
|
|
70
|
+
path: dist/
|
|
71
|
+
|
|
72
|
+
- name: Publish package to PyPI
|
|
73
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
|
|
2
|
+
# QueueLens SDK — Event Delivery Guarantees
|
|
3
|
+
|
|
4
|
+
## Overview
|
|
5
|
+
|
|
6
|
+
The QueueLens SDK captures Celery task lifecycle events and asynchronously
|
|
7
|
+
transmits them to the QueueLens ingestion API.
|
|
8
|
+
|
|
9
|
+
The SDK is designed to observe customer workloads without becoming a
|
|
10
|
+
dependency of task execution.
|
|
11
|
+
|
|
12
|
+
Event delivery uses an in-memory bounded buffer, background HTTP delivery,
|
|
13
|
+
and retry handling.
|
|
14
|
+
|
|
15
|
+
## 1. Event buffering
|
|
16
|
+
|
|
17
|
+
The SDK maintains an in-memory event buffer.
|
|
18
|
+
|
|
19
|
+
Default configuration:
|
|
20
|
+
|
|
21
|
+
| Setting | Default |
|
|
22
|
+
|---|---:|
|
|
23
|
+
| Buffer capacity | 1,000 events |
|
|
24
|
+
| Batch size | 100 events |
|
|
25
|
+
| Flush interval | 5 seconds |
|
|
26
|
+
| Maximum batches per cycle | 10 |
|
|
27
|
+
|
|
28
|
+
Events are added to the buffer when Celery lifecycle signals are received.
|
|
29
|
+
|
|
30
|
+
The buffer is bounded to prevent unbounded memory consumption.
|
|
31
|
+
|
|
32
|
+
### Buffer overflow
|
|
33
|
+
|
|
34
|
+
When the buffer reaches capacity:
|
|
35
|
+
|
|
36
|
+
- New events are rejected.
|
|
37
|
+
- Existing buffered events are retained.
|
|
38
|
+
- The dropped event counter is incremented.
|
|
39
|
+
- A warning is logged.
|
|
40
|
+
|
|
41
|
+
The SDK exposes the dropped event count through its instrumentation instance.
|
|
42
|
+
|
|
43
|
+
## 2. Event transmission
|
|
44
|
+
|
|
45
|
+
The SDK sends buffered events to the QueueLens ingestion API using HTTP.
|
|
46
|
+
|
|
47
|
+
Each request contains a batch of events.
|
|
48
|
+
|
|
49
|
+
Authentication uses the configured QueueLens API key.
|
|
50
|
+
|
|
51
|
+
The SDK acknowledges events only after:
|
|
52
|
+
|
|
53
|
+
1. The HTTP request succeeds.
|
|
54
|
+
2. The ingestion response can be validated.
|
|
55
|
+
3. The accepted and duplicate counts match the submitted batch size.
|
|
56
|
+
|
|
57
|
+
Events that fail delivery remain in the buffer.
|
|
58
|
+
|
|
59
|
+
## 3. Retry behavior
|
|
60
|
+
|
|
61
|
+
When event delivery fails, the SDK retains the events for another attempt.
|
|
62
|
+
|
|
63
|
+
The background flusher uses exponential backoff with equal jitter.
|
|
64
|
+
|
|
65
|
+
Default retry settings:
|
|
66
|
+
|
|
67
|
+
| Setting | Default |
|
|
68
|
+
|---|---:|
|
|
69
|
+
| Initial backoff | 1 second |
|
|
70
|
+
| Maximum backoff | 30 seconds |
|
|
71
|
+
| Retry strategy | Exponential backoff with equal jitter |
|
|
72
|
+
|
|
73
|
+
A successful delivery cycle resets the retry backoff.
|
|
74
|
+
|
|
75
|
+
Retry attempts continue while the worker process remains alive.
|
|
76
|
+
|
|
77
|
+
## 4. Duplicate event handling
|
|
78
|
+
|
|
79
|
+
Each event has a unique event ID.
|
|
80
|
+
|
|
81
|
+
The ingestion backend uses this ID to identify duplicate events.
|
|
82
|
+
|
|
83
|
+
If an event was committed by the backend but the SDK did not receive the response, the SDK may transmit that event again.
|
|
84
|
+
|
|
85
|
+
The backend deduplicates the repeated event ID.
|
|
86
|
+
|
|
87
|
+
This provides duplicate-safe ingestion, but does not guarantee exactly-once delivery.
|
|
88
|
+
|
|
89
|
+
## 5. Shutdown behavior
|
|
90
|
+
|
|
91
|
+
During graceful shutdown:
|
|
92
|
+
|
|
93
|
+
1. The SDK signals the background flusher to stop.
|
|
94
|
+
2. The flusher waits for an in-progress delivery operation to finish.
|
|
95
|
+
3. The flusher makes one final delivery attempt.
|
|
96
|
+
4. The HTTP client is closed after the flusher exits.
|
|
97
|
+
|
|
98
|
+
The shutdown operation has a configurable timeout.
|
|
99
|
+
|
|
100
|
+
If the flusher does not stop within that timeout, it may continue running in the background until its current operation completes.
|
|
101
|
+
|
|
102
|
+
A shutdown timeout does not forcibly terminate the background thread.
|
|
103
|
+
|
|
104
|
+
## 6. Process termination and data loss
|
|
105
|
+
|
|
106
|
+
The current SDK uses in-memory buffering.
|
|
107
|
+
|
|
108
|
+
Pending events may be lost when:
|
|
109
|
+
|
|
110
|
+
- A worker process crashes.
|
|
111
|
+
- A container is forcefully terminated.
|
|
112
|
+
- The operating system kills the process.
|
|
113
|
+
- A machine loses power.
|
|
114
|
+
- The process exits before buffered events are delivered.
|
|
115
|
+
|
|
116
|
+
The SDK does not currently persist pending events to disk.
|
|
117
|
+
|
|
118
|
+
Graceful shutdown attempts to deliver pending events, but a final failed attempt can still leave events undelivered.
|
|
119
|
+
|
|
120
|
+
## 7. Failure isolation
|
|
121
|
+
|
|
122
|
+
QueueLens instrumentation failures must not interrupt customer task execution.
|
|
123
|
+
|
|
124
|
+
The SDK handles its own event capture and delivery failures independently.
|
|
125
|
+
|
|
126
|
+
Examples include:
|
|
127
|
+
|
|
128
|
+
- Event serialization failures.
|
|
129
|
+
- Buffer insertion failures.
|
|
130
|
+
- HTTP transport failures.
|
|
131
|
+
- Invalid ingestion responses.
|
|
132
|
+
- Background flusher initialization failures.
|
|
133
|
+
- Shutdown failures.
|
|
134
|
+
|
|
135
|
+
QueueLens does not suppress exceptions raised by the customer's actual Celery task.
|
|
136
|
+
|
|
137
|
+
## 8. Delivery guarantee
|
|
138
|
+
|
|
139
|
+
The current SDK provides:
|
|
140
|
+
|
|
141
|
+
- In-memory event buffering.
|
|
142
|
+
- Bounded memory usage.
|
|
143
|
+
- Background HTTP transmission.
|
|
144
|
+
- Retention and retries during process lifetime.
|
|
145
|
+
- Duplicate-safe ingestion.
|
|
146
|
+
- Best-effort graceful shutdown delivery.
|
|
147
|
+
|
|
148
|
+
The current SDK does not provide:
|
|
149
|
+
|
|
150
|
+
- Durable event storage.
|
|
151
|
+
- Guaranteed delivery after process crashes.
|
|
152
|
+
- Exactly-once delivery.
|
|
153
|
+
- Guaranteed delivery when the backend remains unavailable.
|
|
154
|
+
- Persistent recovery of buffered events after a restart.
|
|
155
|
+
|
|
156
|
+
## 9. Configuration example
|
|
157
|
+
|
|
158
|
+
The SDK can be configured through environment variables.
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
QUEUELENS_API_KEY=ql_test_your_api_key
|
|
162
|
+
QUEUELENS_ENDPOINT=https://api.example.com/internal/v1/events/batch
|
|
163
|
+
|
|
164
|
+
QUEUELENS_BATCH_SIZE=100
|
|
165
|
+
QUEUELENS_FLUSH_INTERVAL=5
|
|
166
|
+
QUEUELENS_TIMEOUT=5
|
|
167
|
+
QUEUELENS_BUFFER_CAPACITY=1000
|
|
168
|
+
QUEUELENS_MAX_BATCHES_PER_CYCLE=10
|
|
169
|
+
QUEUELENS_SHUTDOWN_TIMEOUT=10
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Explicit constructor arguments take precedence over environment variables.
|
|
173
|
+
|
|
174
|
+
See the SDK configuration reference for all supported settings.
|
|
175
|
+
|
|
176
|
+
## 10. Future improvements
|
|
177
|
+
|
|
178
|
+
Potential future reliability improvements include:
|
|
179
|
+
|
|
180
|
+
- Optional disk-backed event persistence.
|
|
181
|
+
- Recovery of pending events after process restart.
|
|
182
|
+
- Configurable overflow strategies.
|
|
183
|
+
- Delivery health metrics.
|
|
184
|
+
- Persistent delivery acknowledgments.
|
|
185
|
+
- Improved visibility into dropped and undelivered events.
|
|
186
|
+
|
|
187
|
+
These features are not part of the current SDK implementation.
|
queuelens-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 [Your Legal Name or Company Name]
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
queuelens-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: queuelens
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python SDK for background job observability and Celery instrumentation
|
|
5
|
+
Project-URL: Homepage, https://github.com/muhammedsafuvan/qlens-sdk
|
|
6
|
+
Project-URL: Repository, https://github.com/muhammedsafuvan/qlens-sdk
|
|
7
|
+
Project-URL: Issues, https://github.com/muhammedsafuvan/qlens-sdk/issues
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Python: >=3.12
|
|
11
|
+
Requires-Dist: httpx>=0.28.1
|
|
12
|
+
Requires-Dist: pydantic>=2.0
|
|
13
|
+
Provides-Extra: celery
|
|
14
|
+
Requires-Dist: celery[redis]>=5.6.3; extra == 'celery'
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# QueueLens Python SDK
|
|
18
|
+
|
|
19
|
+
QueueLens provides background job observability for Python applications using Celery.
|
|
20
|
+
|
|
21
|
+
It instruments Celery task lifecycle events and asynchronously delivers them to your QueueLens instance, allowing you to monitor job execution, failures, retries, and worker activity.
|
|
22
|
+
|
|
23
|
+
## Requirements
|
|
24
|
+
|
|
25
|
+
- Python 3.12+
|
|
26
|
+
- Celery 5.6+
|
|
27
|
+
- A running QueueLens instance
|
|
28
|
+
- A QueueLens workspace API key
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
Install the SDK with Celery support:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install "queuelens[celery]"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This installs QueueLens and its optional Celery integration dependencies.
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
The recommended integration is **Standard Integration**.
|
|
43
|
+
|
|
44
|
+
### 1. Configure environment variables
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
export QUEUELENS_API_KEY="ql_test_your_api_key"
|
|
48
|
+
export QUEUELENS_ENDPOINT="http://localhost:8001/internal/v1/events/batch"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Replace the example API key and endpoint with the credentials and ingestion endpoint provided by your QueueLens deployment.
|
|
52
|
+
|
|
53
|
+
### 2. Instrument your Celery application
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from celery import Celery
|
|
57
|
+
from queuelens import QueueLens
|
|
58
|
+
|
|
59
|
+
app = Celery("orders")
|
|
60
|
+
|
|
61
|
+
queuelens = QueueLens()
|
|
62
|
+
queuelens.instrument(app)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
That's it. QueueLens automatically registers its Celery signal handlers and manages event delivery through a background flusher.
|
|
66
|
+
|
|
67
|
+
You do not need to modify your existing task definitions.
|
|
68
|
+
|
|
69
|
+
### 3. Run your worker
|
|
70
|
+
|
|
71
|
+
Start your Celery worker as usual:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
celery -A your_module.app worker --loglevel=info
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Your task lifecycle events will be captured and delivered to QueueLens.
|
|
78
|
+
|
|
79
|
+
## Configuration
|
|
80
|
+
|
|
81
|
+
QueueLens supports configuration through constructor arguments or environment variables.
|
|
82
|
+
|
|
83
|
+
Constructor arguments take precedence over environment variables, which take precedence over defaults.
|
|
84
|
+
|
|
85
|
+
| Parameter | Environment variable | Default |
|
|
86
|
+
|---|---|---:|
|
|
87
|
+
| `api_key` | `QUEUELENS_API_KEY` | Required |
|
|
88
|
+
| `endpoint` | `QUEUELENS_ENDPOINT` | Required |
|
|
89
|
+
| `batch_size` | `QUEUELENS_BATCH_SIZE` | 100 |
|
|
90
|
+
| `flush_interval` | `QUEUELENS_FLUSH_INTERVAL` | 5 seconds |
|
|
91
|
+
| `timeout` | `QUEUELENS_TIMEOUT` | 5 seconds |
|
|
92
|
+
| `buffer_capacity` | `QUEUELENS_BUFFER_CAPACITY` | 1,000 |
|
|
93
|
+
| `max_batches_per_cycle` | `QUEUELENS_MAX_BATCHES_PER_CYCLE` | 10 |
|
|
94
|
+
| `shutdown_timeout` | `QUEUELENS_SHUTDOWN_TIMEOUT` | 10 seconds |
|
|
95
|
+
|
|
96
|
+
### Configure using Python
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
from celery import Celery
|
|
100
|
+
from queuelens import QueueLens
|
|
101
|
+
|
|
102
|
+
app = Celery("orders")
|
|
103
|
+
|
|
104
|
+
queuelens = QueueLens(
|
|
105
|
+
api_key="ql_test_your_api_key",
|
|
106
|
+
endpoint="http://localhost:8001/internal/v1/events/batch",
|
|
107
|
+
batch_size=100,
|
|
108
|
+
flush_interval=5,
|
|
109
|
+
timeout=5,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
queuelens.instrument(app)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Configure using environment variables
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
export QUEUELENS_API_KEY="ql_test_your_api_key"
|
|
119
|
+
export QUEUELENS_ENDPOINT="http://localhost:8001/internal/v1/events/batch"
|
|
120
|
+
|
|
121
|
+
export QUEUELENS_BATCH_SIZE=100
|
|
122
|
+
export QUEUELENS_FLUSH_INTERVAL=5
|
|
123
|
+
export QUEUELENS_TIMEOUT=5
|
|
124
|
+
export QUEUELENS_BUFFER_CAPACITY=1000
|
|
125
|
+
export QUEUELENS_MAX_BATCHES_PER_CYCLE=10
|
|
126
|
+
export QUEUELENS_SHUTDOWN_TIMEOUT=10
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Keep API keys in environment variables or a secrets manager. Do not commit credentials to source control.
|
|
130
|
+
|
|
131
|
+
## Captured events
|
|
132
|
+
|
|
133
|
+
QueueLens captures the following Celery task lifecycle events:
|
|
134
|
+
|
|
135
|
+
| Event | Description |
|
|
136
|
+
|---|---|
|
|
137
|
+
| `received` | Task received by a worker |
|
|
138
|
+
| `started` | Task execution started |
|
|
139
|
+
| `succeeded` | Task completed successfully |
|
|
140
|
+
| `failed` | Task execution failed |
|
|
141
|
+
| `retried` | Task was scheduled for retry |
|
|
142
|
+
|
|
143
|
+
Each event includes available metadata such as:
|
|
144
|
+
|
|
145
|
+
- Task ID
|
|
146
|
+
- Task name
|
|
147
|
+
- Event type
|
|
148
|
+
- Event timestamp
|
|
149
|
+
- Worker name
|
|
150
|
+
- Queue name
|
|
151
|
+
- Attempt number
|
|
152
|
+
|
|
153
|
+
The attempt number is derived from Celery's retry count.
|
|
154
|
+
|
|
155
|
+
## Event delivery
|
|
156
|
+
|
|
157
|
+
QueueLens delivers events asynchronously so that instrumentation does not need to wait for HTTP requests during task execution.
|
|
158
|
+
|
|
159
|
+
The SDK uses:
|
|
160
|
+
|
|
161
|
+
- A bounded in-memory event buffer.
|
|
162
|
+
- Configurable batch sizes.
|
|
163
|
+
- Periodic background flushing.
|
|
164
|
+
- HTTP timeouts.
|
|
165
|
+
- Automatic retries with exponential backoff and jitter.
|
|
166
|
+
- Event acknowledgement after successful ingestion.
|
|
167
|
+
- A final delivery attempt during graceful shutdown.
|
|
168
|
+
|
|
169
|
+
### Retry behavior
|
|
170
|
+
|
|
171
|
+
When delivery fails, events remain in the buffer and are retried.
|
|
172
|
+
|
|
173
|
+
The retry delay uses exponential backoff, starting at approximately one second and increasing up to 30 seconds, with jitter.
|
|
174
|
+
|
|
175
|
+
Events are acknowledged only after the ingestion response is successfully received and validated.
|
|
176
|
+
|
|
177
|
+
QueueLens uses event IDs to support duplicate-safe ingestion. This provides retry-safe delivery behavior, not exactly-once delivery.
|
|
178
|
+
|
|
179
|
+
## Graceful shutdown
|
|
180
|
+
|
|
181
|
+
QueueLens automatically integrates with Celery worker lifecycle signals.
|
|
182
|
+
|
|
183
|
+
When a worker shuts down, the SDK:
|
|
184
|
+
|
|
185
|
+
1. Stops the background event flusher.
|
|
186
|
+
2. Attempts to deliver remaining buffered events.
|
|
187
|
+
3. Closes its HTTP client.
|
|
188
|
+
|
|
189
|
+
You generally do not need to manage the SDK lifecycle manually.
|
|
190
|
+
|
|
191
|
+
For explicit cleanup, you can call:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
queuelens.close()
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Do not call this while the Celery worker is still expected to capture events.
|
|
198
|
+
|
|
199
|
+
## Reliability and limitations
|
|
200
|
+
|
|
201
|
+
QueueLens is designed to keep observability failures isolated from application task execution.
|
|
202
|
+
|
|
203
|
+
However, there are important limitations:
|
|
204
|
+
|
|
205
|
+
- **In-memory buffering:** Events are held in process memory and are not persisted to disk.
|
|
206
|
+
- **Process termination:** A crash, forceful termination, or machine failure can result in loss of pending events.
|
|
207
|
+
- **Buffer capacity:** When the buffer is full, new events are dropped and the SDK logs a warning.
|
|
208
|
+
- **Network failures:** Failed deliveries are retried while the process remains alive and events remain buffered.
|
|
209
|
+
- **Graceful shutdown:** The SDK makes a final delivery attempt, but delivery is not guaranteed if the endpoint remains unavailable or the shutdown timeout is exceeded.
|
|
210
|
+
|
|
211
|
+
The SDK should be treated as an observability integration, not as a replacement for Celery's task reliability mechanisms.
|
|
212
|
+
|
|
213
|
+
## Logging
|
|
214
|
+
|
|
215
|
+
QueueLens uses Python's standard logging module.
|
|
216
|
+
|
|
217
|
+
To enable debug-level SDK logs:
|
|
218
|
+
|
|
219
|
+
```python
|
|
220
|
+
import logging
|
|
221
|
+
|
|
222
|
+
logging.basicConfig(level=logging.INFO)
|
|
223
|
+
logging.getLogger("queuelens").setLevel(logging.DEBUG)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
This can help diagnose event capture, delivery failures, retries, and buffer overflow.
|
|
227
|
+
|
|
228
|
+
## Example application
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
from celery import Celery
|
|
232
|
+
from queuelens import QueueLens
|
|
233
|
+
|
|
234
|
+
app = Celery(
|
|
235
|
+
"orders",
|
|
236
|
+
broker="redis://localhost:6379/0",
|
|
237
|
+
backend="redis://localhost:6379/1",
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
queuelens = QueueLens()
|
|
241
|
+
queuelens.instrument(app)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
@app.task
|
|
245
|
+
def process_order(order_id: str):
|
|
246
|
+
print(f"Processing order: {order_id}")
|
|
247
|
+
return {"order_id": order_id, "status": "completed"}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
Run the worker:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
celery -A app worker --loglevel=info
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
See the repository's license information.
|