Skip to main content

A Redis-backed Python job queue with rate limiting, delayed jobs, retries, and real-time queue control.

Project description

Run tests and upload coverage codecov

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 unixsocket lines in your redis.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; pass queue_type and/or queue_id for 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 to localhost: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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tailback-1.0.0.tar.gz (15.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tailback-1.0.0-py3-none-any.whl (22.6 kB view details)

Uploaded Python 3

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

Hashes for tailback-1.0.0.tar.gz
Algorithm Hash digest
SHA256 e4f7108628551e69a6164b8ddf59a284417a788048e21eaab965c96ce3e8bfd4
MD5 a2fcc06371e1e2046161fac2c14de32e
BLAKE2b-256 8004df578a4fe610ee93f172026af203165f77899d24c81ac2fb90b0bc3e9090

See more details on using hashes here.

Provenance

The following attestation bundles were made for tailback-1.0.0.tar.gz:

Publisher: pypi.yml on flowdacity/tailback

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for tailback-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 47eec173540d53c939ddf263cfe1be91f52da32e8e5ca60f894ae29491e66f67
MD5 5627e66cd4ccad7ce217f3a5951feaf4
BLAKE2b-256 c038514917ef7505bcd19203c24dc62a278776a30d8391c1f837bbfbfbaf11ca

See more details on using hashes here.

Provenance

The following attestation bundles were made for tailback-1.0.0-py3-none-any.whl:

Publisher: pypi.yml on flowdacity/tailback

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page