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.
@@ -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,18 @@
1
+ # Virtual environments
2
+ .venv/
3
+ .venv-*/
4
+ venv/
5
+
6
+ # Build artifacts
7
+ dist/
8
+ build/
9
+ *.egg-info/
10
+
11
+ # Python cache
12
+ __pycache__/
13
+ *.py[cod]
14
+
15
+ # Test and tooling caches
16
+ .pytest_cache/
17
+ .ruff_cache/
18
+ .mypy_cache/
@@ -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.
@@ -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.
@@ -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.