Skip to main content

minique /miniːk/

A minimal Redis 4.0+/Valkey job queue for Python 3.10 and above.

Requirements

Client

  • Python 3.10+
  • Either redis-py 2.10+, or valkey 6.0

Server

  • A Redis 4.0+ or Valkey server

Usage

  • Have a Redis 4.0+ or Valkey server running.

Client

from redis import Redis  # (or from valkey import Valkey as Redis)
from minique.api import enqueue, get_job

# Get a Redis connection, somehow.
redis = Redis.from_url('redis://localhost:6379/4')

job = enqueue(
    redis=redis,
    queue_name='work',
    callable='my_jobs.calcumacalate',  # Dotted path to your callable.
    kwargs={'a': 5, 'b': 5},  # Only kwargs supported.
    # You can also set a `job_id` yourself (but it must be unique)
)

job_id = job.id  # Save the job ID somewhere, maybe?

while not job.has_finished:
    pass  # Twiddle thumbs...

print(job.result)  # Okay!

# Get the same job later (though not later than 7 days (by default)):
job = get_job(redis, job_id)

Worker(s)

  • Ensure your workers are able to import the functions you wish to run.
  • Set the callables the worker will allow with --allow-callable.
    • Alternately, you may wish to subclass minique.work.job_runner.JobRunner to specify an entirely different lookup mechanism.
$ minique -u redis://localhost:6379/4 -q work -q anotherqueue -q thirdqueue --allow-callable 'my_jobs.*'

Priority Queues

Minique supports priority queueing as an optional feature using the enqueue_priority API.

Priority queues are compatible with standard workers. However, priority is implemented using a helper data structure, requiring the client needs to call job.cleanup() after each job and/or PriorityQueue(...).periodic_clean() to prune this structure of jobs that have already been processed.

Priority queue requires Lua scripting permissions from the Redis queue service.

from redis import Redis  # (or from valkey import Valkey as Redis)
from minique.api import enqueue_priority, get_job

# Get a Redis connection, somehow.
redis = Redis.from_url('redis://localhost:6379/4')

job = enqueue_priority(
    redis=redis,
    queue_name='urgent_work',
    callable='my_jobs.calcumacalate',  # Dotted path to your callable.
    kwargs={'a': 5, 'b': 5},  # Only kwargs supported.
    priority=1,  # Integer
    # You can also set a `job_id` yourself (but it must be unique)
)

job_id = job.id  # Save the job ID somewhere, maybe?

while not job.has_finished:
    pass  # Twiddle thumbs...

print(job.result)  # Okay!

# Job priorities are stored in a helper hash table which should be cleaned using this method
# after the job has left the queue.
job.cleanup()

# Get the same job later (though not later than 7 days (by default)):
job = get_job(redis, job_id)

Affinity

Jobs can carry one or more opaque affinity specifiers — typically identifiers for something expensive to fetch, for instance. A worker that recently ran a job with a given specifier becomes "warm" for it and prefers to pick up further jobs with the same specifier.

This is purely an optimization and never a constraint. Workers may always end up pulling jobs from the base queue, and jobs may be picked up by any worker regardless of affinity.

from minique.api import enqueue

# Two jobs that both need the same large dataset will prefer the same worker:
job_a = enqueue(redis, 'training', 'my_jobs.train', kwargs={'fold': 0}, affinity=['dataset-42'])
job_b = enqueue(redis, 'training', 'my_jobs.train', kwargs={'fold': 1}, affinity=['dataset-42'])

enqueue_priority accepts affinity too; each affinity sub-queue is itself a priority queue, so ordering within a specifier still respects priority.

Affinity outranks priority on a warm worker. Because a warm worker checks its affinity sub-queues before the base queue, it can pick up a lower-priority affine job ahead of a higher-priority job waiting in the base priority queue.

Cleaning up sub-queue residue

Affinity sub-queues self-heal while jobs for a specifier keep flowing. Once a specifier goes quiet, a little residue can linger (phantom ids for expired jobs, and orphaned …prio hashes for priority queues). Trim it on demand with

minique.api.clean_affinity_sub_queues(redis, base_queue_name, priority=...).

The call is idempotent, best-effort, and safe to run concurrently from many workers, so the simplest approach is to fire it occasionally with e.g. random.random() < 0.01.

Library support

orjson

If orjson is installed, it will automatically be used for faster JSON serialization and deserialization of job arguments and results.

Sentry

Minique automatically integrates with the Sentry exception tracking service.

You can use the [sentry] installation extra to install sentry-sdk along with Minique, or you can do it manually.

Simply set the SENTRY_DSN environment variable; if all goes well, you should see a "Sentry configured with a valid DSN" message at CLI boot.

The other environment-configurable options also work as you would expect.

Exceptions occurring during job execution will be sent to Sentry and annotated with minique context describing the job ID and queue name.

Development

# install `minique` in editable mode with development dependencies
pip install -e .[sentry,test] pre-commit mypy==1.0.0 types-redis && pre-commit install

# run lints
pre-commit run --all-files

# run type checks
mypy --strict --install-types --show-error-codes minique

# run tests against the specified Redis database
REDIS_URL=redis://localhost:6379/0 pytest .

Release

# decide on a new version number and set it
vim minique/__init__.py
__version__ = "0.9.0"

npx auto-changelog --commit-limit=0 -v 0.9.0

# undo changes changelog generation did to the older entries

git add -u
git commit -m "Become 0.9.0"
git tag -m "v0.9.0" -a v0.9.0

git push --follow-tags

Release files for minique 0.12.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for minique 0.12.0
File Size Uploaded
minique-0.12.0.tar.gz 20.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for minique 0.12.0
File Interpreter ABI Platform
minique-0.12.0-py3-none-any.whl Python 3 none any Details

Total release size: 48.7 kB

Release files / minique-0.12.0.tar.gz

Download URL minique-0.12.0.tar.gz
Size 20.4 kB
Tags Source
SHA-256 checksum
How to use checksums
9eb065aba65b726a401b44a94781bcd8a888ee7d7219fbd0f2952c3e466cf301
BLAKE2b-256 checksum
How to use checksums
b9e34595280028a6a8c74ca83824cc3542fd58e7849e5e1bfa223239b83547d4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / minique-0.12.0-py3-none-any.whl

Download URL minique-0.12.0-py3-none-any.whl
Size 28.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5b48ff93f97326352905dd32bd1b087e4e9a088ae55211dd3ca9dfe9f96adc0d
BLAKE2b-256 checksum
How to use checksums
c8023540c35eba1f4bcbe73d7cca2ebbbe37dcb68a17220635f78d18c992c4d9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.12.0 This release

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page