Skip to content

Releases: coleifer/huey

3.3.0

Choose a tag to compare

@coleifer coleifer released this 22 Jul 15:45
  • Add retry_backoff parameter to task() and periodic_task(). The first retry waits retry_delay seconds and each subsequent delay is multiplied by retry_backoff, giving exponentially-growing waits between retries.
  • Fix create_tables=False, which crashed SqliteHuey at connect and was silently ignored by the peewee SqlHuey. SqlStorage also gains initialize_schema() so the create_huey_tables command supports it.
  • Accept float priorities in FileStorage by truncating to int. Previously they raised a TypeError.
  • Raise ResultTimeout from blocking Result.get() when the wait ends w/o an obtainable result, e.g. a dropped connection. Previously the internal EmptyData sentinel could be returned.
  • Preserve per-call retry_backoff when a task is rescheduled via Result.reschedule().
  • Clear revocations that arrive mid-execution w/ a delete, so the clear also works on RedisExpireHuey where destructive reads do not remove data.
  • Fix an off-by-one in the redis scheduled_items() that returned limit+1 items.
  • Reconnect stale connections in the SqlHuey counter methods, which run in the consumer via chords and rate limits.
  • Return the lock from TaskLock.__enter__(), so with huey.lock_task('x') as lock: binds the lock instead of None.
  • Defer the redis server version check to first use. Previously every storage init issued an INFO round-trip.
  • Remove the undocumented Kyoto Tycoon storage backend, its tests, and the ukt CI dependency.
  • Remove the djhuey backend_class alias for huey_class (deprecated since 2.0) and the Django <1.2 settings.DATABASE_NAME queue-name fallback.
  • Fire the chord callback when a pipelined member dies before its tail. A failed, revoked, or expired stage now contributes for the member, where previously the chord counter stayed short and the callback never ran.
  • Add CySqliteHuey, which drives the sqlite storage w/ cysqlite instead of the stdlib sqlite3 module and takes an open-ended pragmas dict in place of a fixed set of tuning parameters.

View commits

im-d027a54447

3.2.1

Choose a tag to compare

@coleifer coleifer released this 09 Jul 21:22
  • Add a Django admin dashboard for task statistics. Adding huey.contrib.djhuey.stats to INSTALLED_APPS starts the huey.contrib.stats recorder in every process (incl. the consumer) and adds a Huey section to the admin: a dashboard w/ the same live stats and controls as the flask-peewee panel, plus a filterable event log. Stats are stored via peewee in the default Django database and require no migrations.

View commits

django-admin

3.2.0

Choose a tag to compare

@coleifer coleifer released this 09 Jul 17:38
  • Add store_intermediate_errors option (default true, preserving current behavior). When false, a task that fails with retries remaining no longer writes its exception to the result store or runs its on_error handler until the retries are exhausted, so a blocking Result.get() waits for the final outcome instead of raising on the first failed attempt.
  • Add create_tables option to the SQL storage backends (default true). Pass create_tables=False to skip the automatic create table if not exists at init, e.g. to manage huey's schema via Django migrations rather than have every web worker attempt DDL on import.
  • Add a create_huey_tables Django management command to create the tables when create_tables=False.
  • Fix on_error handlers accumulating one exception argument per failed attempt across retries. Handlers now receives only the current attempt's exception.
  • Add huey.contrib.stats, a task-statistics engine: enable_stats(huey, db) records task signals into two peewee tables (huey_event, huey_inflight) and exposes a HueyStats query API for throughput, per-task timing, error-rates, in-flight and recent-event views. Depends only on peewee, so it can back a custom dashboard or exporter; enable it in the consumer to capture task execution.
  • Add a Flask-Peewee admin panel, huey.contrib.flask_admin.HueyPanel, registered w/ admin.register_panel('Huey', HueyPanel, huey). It renders the recorded stats as a dashboard card plus a standalone page with live queue depths, throughput, per-task stats, running tasks and recent events. Has controls to revoke/restore tasks and flush the queue, schedule, results or locks. Requires flask-peewee 4.0.1+.

View commits

Admin integration for flask-peewee

flask-admin-panel-dashboard

Detail view

flask-admin-panel flask-admin-tasks

3.1.1

Choose a tag to compare

@coleifer coleifer released this 02 Jul 22:10
  • Ensure we use a safe name for long postgres queue names. PG has a 63 byte limit on the channel name.
  • Ensure recycled worker threads no longer leak their LISTEN connections w/Postgres.

View commits
im-4b2b453e9b

3.1.0

Choose a tag to compare

@coleifer coleifer released this 02 Jul 20:57
  • Add first-class Postgres support: PostgresHuey. Workers use LISTEN/NOTIFY when a task is enqueued, giving Redis-like dequeue latency without polling, and dequeues use select ... for update skip locked so any number of consumers can share one database (requires psycopg 3.2+).
  • The django.tasks backend is now also compatible with the django-tasks backport package, extending support to pre-6.0 Django.
  • Use an explicit fork multiprocessing context for process workers, rather than setting the global start-method from the consumer entry-points. Fixes -k process on MacOS 3.8+ / Linux 3.14+ when the consumer is started via the huey_consumer console-script or a programmatic create_consumer().run().

View commits

3.0.3

Choose a tag to compare

@coleifer coleifer released this 02 Jul 20:58

3.0.3

  • Add a Django 6.0 task backend - pretty much works the same way the normal
    Django integration works (manage.py run_huey), but using Django's canonical
    APIs and decorator. Docs here.

View commits

3.0.2

Choose a tag to compare

@coleifer coleifer released this 11 Jun 13:34
  • Redis blocking dequeue no longer swallows ConnectionError -- the error propagates to the worker, which logs it and applies exponential backoff. Previously a downed redis server caused workers to busy-loop silently.
  • Chord callbacks now fire when a member task is revoked, expired or cancelled by a pre-execute hook -- the skipped member contributes a None placeholder result. Previously the callback was silently lost.
  • Scheduler skips missed periodic checks after a stall (e.g. suspend/resume) instead of running them back-to-back, which enqueued duplicate periodic tasks for the current minute.
  • Fix inverted timeout clamp in wait_result() when using notify_result with redis < 6 (or an unknown server version): timeouts over one second were cut to 1s, and sub-second timeouts blocked indefinitely.
  • put_if_empty() is now atomic for the memory and file storage backends, restoring lock_task() mutual exclusion on those backends.
  • FileLock no longer unlinks an existing lock file at construction time, which broke mutual exclusion for any process already holding the lock.
  • Process-worker task timeouts use signal.setitimer(), so float / sub-second timeouts work. Previously a timeout less than 1 second was silently ignored (alarm(0) cancels the timer) and fractional seconds were truncated.
  • Consumer signal handlers only set flags -- logging and greenlet cleanup now happen in the main loop, avoiding re-entrant I/O from signal context.
  • A user-supplied task kwarg named task is no longer dropped during serialization. Context tasks (context=True) inject the task instance into a copy of the kwargs rather than mutating the task's data.
  • MemoryStorage.dequeue() and add_to_schedule() acquire the storage lock, like the other mutating methods.
  • normalize_time() treats delay=0 as "now" rather than ignoring it, so e.g. expires=0 means "expires immediately" instead of "never expires".
  • Redis enqueued_items(limit) returned limit + 1 items from the producer end of the queue; it now returns the next-limit items to be dequeued, matching the other storage backends.
  • Redis-dependent tests are skipped when no local redis server is reachable, instead of failing at import time.

View commits

im-d573b49828

3.0.1

Choose a tag to compare

@coleifer coleifer released this 14 May 15:36
  • Fix bug in redis version parsing when using Elasticache or any other that sends major/minor. redis-py incorrectly parses these as floats because there's only a single decimal, so the version check was breaking.
  • Rename max task option --max-tasks (previously was --max_tasks).

View commits

3.0.0

Choose a tag to compare

@coleifer coleifer released this 14 Apr 20:08

Good things come in THREEs

Three-Witches-oil-Banquo-Macbeth-Henry-Fuseli

  • Add chord() (map -> reduce) and group() (map) primitives.
  • Add timeout (using SIGALRM for process and gevent.Timeout for greenlet) to control task running time. For threads, unfortunately, there's no good mechanism so instead APIs for cooperatively checking timeout are provided on the Task instance.
  • Add simple fixed-window rate_limit() for tasks.
  • Add Result.is_ready() method for checking result readiness.
  • New option for low-latency result fetching, available for RedisHuey. To use, pass notify_result=True when initializing your Huey instance.
  • Add new incr(key, amount=1) to storage API for atomic increment primitive. This is used by chord().
  • Add new wait_result() method to storage APIs for efficiently waiting for a result to become ready. The default implementation uses the exponential backoff from the previous implementation of a blocking Result.get() - so no changes are needed. However if you have a custom storage implementation, this provides a mechanism for pub/sub or other notification of result readiness.
  • Remove Python 2.x compatibility.

View commits

2.6.0

Choose a tag to compare

@coleifer coleifer released this 06 Jan 03:11

We have entered the brave new world of using pyproject.toml and github actions to shovel our shitty open-source software into our users docker containers and venvs and whatever other layers of abstraction I'm too geriatric to have heard about (no I will NOT put my hearing aids in). Welcome to the future, it is looking hellish. I had to beg the assistance of a chatbot trained on other shitty open-source projects to slap this together, nor do I understand what I was copying and pasting. Fellow travelers through the realms of ancient Night and Chaos, take comfort that at least the feeling is an old one.

Me miserable! Which way shall I fly
Infinite wrath and infinite despair?
Which way I fly is hell; myself am hell;
And in the lowest deep a lower deep,
Still threat'ning to devour me, opens wide,
To which the hell I suffer seems a heaven.

Python(r), putting the snake oil in your build system.

im-742836677f