A Redis-backed Python job queue with rate limiting, delayed jobs, retries, and real-time queue control.
Project description
Tailback
Tailback is a flexible, open-source, rate-limited queuing system. Based on the Leaky Bucket Algorithm, Tailback lets you create queues dynamically and update their rate limits in real time.
Features
- Dynamic queues with no setup step.
- Per-queue rate limits.
- Live rate limit updates.
- Automatic retries for unfinished jobs.
- Simple queue metrics.
- Async and sync Python support.
Requirements
- Python 3.12+
- Redis 7+ (run your own instance or start the bundled dev container)
Installation
From PyPI:
pip install tailback
From source (editable):
pip install -e .
Configuration
Tailback accepts a simple config mapping. Intervals are in milliseconds.
config = {
"queue": {
"key_prefix": "queue_server",
"job_expire_interval": 5000,
"job_requeue_interval": 5000,
"default_job_requeue_limit": -1, # -1 retries forever, 0 means no retries
},
"redis": {
"db": 0,
"conn_type": "tcp_sock",
"host": "127.0.0.1",
"port": 6379,
"password": "",
"clustered": False,
},
}
For Unix socket connections, use conn_type: "unix_sock" and provide
unix_socket_path:
"redis": {
"db": 0,
"conn_type": "unix_sock",
"unix_socket_path": "/tmp/redis.sock",
"password": "",
"clustered": False,
}
If you use Unix sockets, uncomment the
unixsocketlines in yourredis.conf:unixsocket /var/run/redis/redis.sock unixsocketperm 755
Async Usage
Import Tailback from the top-level package:
from tailback import Tailback
import asyncio
import uuid
from tailback import Tailback
async def main():
config = {
"queue": {
"key_prefix": "queue_server",
"job_expire_interval": 5000,
"job_requeue_interval": 5000,
"default_job_requeue_limit": -1,
},
"redis": {
"db": 0,
"conn_type": "tcp_sock",
"host": "127.0.0.1",
"port": 6379,
"password": "",
"clustered": False,
},
}
queue = Tailback(config)
await queue.initialize() # connect to Redis and register Lua scripts
job_id = str(uuid.uuid4())
await queue.enqueue(
payload={"message": "hello, world"},
interval=1000, # ms between successful dequeues
job_id=job_id,
queue_id="user001",
queue_type="sms",
)
job = await queue.dequeue(queue_type="sms")
if job["status"] == "success":
# ...process job["payload"]...
await queue.finish(
queue_type="sms",
queue_id=job["queue_id"],
job_id=job["job_id"],
)
await queue.close()
asyncio.run(main())
Sync Usage
Import Tailback from tailback.sync:
import uuid
from tailback.sync import Tailback
config = {
"queue": {
"key_prefix": "queue_server",
"job_expire_interval": 5000,
"job_requeue_interval": 5000,
"default_job_requeue_limit": -1,
},
"redis": {
"db": 0,
"conn_type": "tcp_sock",
"host": "127.0.0.1",
"port": 6379,
"password": "",
"clustered": False,
},
}
queue = Tailback(config)
queue.initialize()
job_id = str(uuid.uuid4())
queue.enqueue(
payload={"message": "hello, world"},
interval=1000,
job_id=job_id,
queue_id="user001",
queue_type="sms",
)
job = queue.dequeue(queue_type="sms")
if job["status"] == "success":
queue.finish(
queue_type="sms",
queue_id=job["queue_id"],
job_id=job["job_id"],
)
queue.close()
Common Operations
await queue.requeue()— move expired jobs back onto their queues.await queue.interval(interval=5000, queue_id="user001", queue_type="sms")— change a queue’s rate limit on the fly.await queue.metrics()— global metrics; passqueue_typeand/orqueue_idfor scoped stats and queue length.await queue.clear_queue(queue_type="sms", queue_id="user001", purge_all=True)— drop queued jobs and their payload/interval metadata.
The same operations are available from tailback.sync.Tailback without await.
Development
- Start Redis for local development:
make redis-up(binds tolocalhost:6379). - Run the suite:
make test(automatically starts and tears down Redis). - Build a wheel:
make build - Install/uninstall from the build:
make install/make uninstall - Stop the dev Redis container:
make redis-down
License
MIT — see LICENSE.txt.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tailback-1.0.0.tar.gz.
File metadata
- Download URL: tailback-1.0.0.tar.gz
- Upload date:
- Size: 15.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e4f7108628551e69a6164b8ddf59a284417a788048e21eaab965c96ce3e8bfd4
|
|
| MD5 |
a2fcc06371e1e2046161fac2c14de32e
|
|
| BLAKE2b-256 |
8004df578a4fe610ee93f172026af203165f77899d24c81ac2fb90b0bc3e9090
|
Provenance
The following attestation bundles were made for tailback-1.0.0.tar.gz:
Publisher:
pypi.yml on flowdacity/tailback
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tailback-1.0.0.tar.gz -
Subject digest:
e4f7108628551e69a6164b8ddf59a284417a788048e21eaab965c96ce3e8bfd4 - Sigstore transparency entry: 1461780951
- Sigstore integration time:
-
Permalink:
flowdacity/tailback@0853cbd9be32543aafa518cc523ac98aacb70349 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/flowdacity
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@0853cbd9be32543aafa518cc523ac98aacb70349 -
Trigger Event:
push
-
Statement type:
File details
Details for the file tailback-1.0.0-py3-none-any.whl.
File metadata
- Download URL: tailback-1.0.0-py3-none-any.whl
- Upload date:
- Size: 22.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47eec173540d53c939ddf263cfe1be91f52da32e8e5ca60f894ae29491e66f67
|
|
| MD5 |
5627e66cd4ccad7ce217f3a5951feaf4
|
|
| BLAKE2b-256 |
c038514917ef7505bcd19203c24dc62a278776a30d8391c1f837bbfbfbaf11ca
|
Provenance
The following attestation bundles were made for tailback-1.0.0-py3-none-any.whl:
Publisher:
pypi.yml on flowdacity/tailback
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tailback-1.0.0-py3-none-any.whl -
Subject digest:
47eec173540d53c939ddf263cfe1be91f52da32e8e5ca60f894ae29491e66f67 - Sigstore transparency entry: 1461780961
- Sigstore integration time:
-
Permalink:
flowdacity/tailback@0853cbd9be32543aafa518cc523ac98aacb70349 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/flowdacity
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi.yml@0853cbd9be32543aafa518cc523ac98aacb70349 -
Trigger Event:
push
-
Statement type: