Releases: coleifer/huey
Release list
3.3.0
- Add
retry_backoffparameter totask()andperiodic_task(). The first retry waitsretry_delayseconds and each subsequent delay is multiplied byretry_backoff, giving exponentially-growing waits between retries. - Fix
create_tables=False, which crashedSqliteHueyat connect and was silently ignored by the peeweeSqlHuey.SqlStoragealso gainsinitialize_schema()so thecreate_huey_tablescommand supports it. - Accept float priorities in
FileStorageby truncating to int. Previously they raised a TypeError. - Raise
ResultTimeoutfrom blockingResult.get()when the wait ends w/o an obtainable result, e.g. a dropped connection. Previously the internalEmptyDatasentinel could be returned. - Preserve per-call
retry_backoffwhen a task is rescheduled viaResult.reschedule(). - Clear revocations that arrive mid-execution w/ a delete, so the clear also works on
RedisExpireHueywhere 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
SqlHueycounter methods, which run in the consumer via chords and rate limits. - Return the lock from
TaskLock.__enter__(), sowith 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_classalias forhuey_class(deprecated since 2.0) and the Django <1.2settings.DATABASE_NAMEqueue-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/cysqliteinstead of the stdlibsqlite3module and takes an open-endedpragmasdict in place of a fixed set of tuning parameters.
3.2.1
- Add a Django admin dashboard for task statistics. Adding
huey.contrib.djhuey.statstoINSTALLED_APPSstarts thehuey.contrib.statsrecorder 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.
3.2.0
- Add
store_intermediate_errorsoption (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 itson_errorhandler until the retries are exhausted, so a blockingResult.get()waits for the final outcome instead of raising on the first failed attempt. - Add
create_tablesoption to the SQL storage backends (default true). Passcreate_tables=Falseto skip the automaticcreate table if not existsat 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_tablesDjango management command to create the tables whencreate_tables=False. - Fix
on_errorhandlers 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 aHueyStatsquery 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+.
Admin integration for flask-peewee
Detail view
3.1.1
- 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.
3.1.0
- Add first-class Postgres support:
PostgresHuey. Workers use LISTEN/NOTIFY when a task is enqueued, giving Redis-like dequeue latency without polling, and dequeues useselect ... for update skip lockedso any number of consumers can share one database (requires psycopg 3.2+). - The django.tasks backend is now also compatible with the
django-tasksbackport package, extending support to pre-6.0 Django. - Use an explicit
forkmultiprocessing context for process workers, rather than setting the global start-method from the consumer entry-points. Fixes-k processon MacOS 3.8+ / Linux 3.14+ when the consumer is started via thehuey_consumerconsole-script or a programmaticcreate_consumer().run().
3.0.3
3.0.2
- 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
Noneplaceholder 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 usingnotify_resultwith 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, restoringlock_task()mutual exclusion on those backends.FileLockno 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
taskis 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()andadd_to_schedule()acquire the storage lock, like the other mutating methods.normalize_time()treatsdelay=0as "now" rather than ignoring it, so e.g.expires=0means "expires immediately" instead of "never expires".- Redis
enqueued_items(limit)returnedlimit + 1items from the producer end of the queue; it now returns the next-limititems 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.
3.0.1
- 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).
3.0.0
Good things come in THREEs
- Add
chord()(map -> reduce) andgroup()(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=Truewhen initializing your Huey instance. - Add new
incr(key, amount=1)to storage API for atomic increment primitive. This is used bychord(). - 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 blockingResult.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.
2.6.0
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.