Claude Code for Huey: Lightweight Python Task Queue — Claude Skills 360 Blog
Blog / AI / Claude Code for Huey: Lightweight Python Task Queue
AI

Claude Code for Huey: Lightweight Python Task Queue

Published: January 25, 2028
Read time: 5 min read
By: Claude Skills 360

Huey is a lightweight Python task queue. pip install huey. Redis backend: from huey import RedisHuey; huey = RedisHuey("myapp", host="localhost"). SQLite: from huey.contrib.mini import MiniHuey; huey = MiniHuey(). SQLite persistent: from huey import SqliteHuey; huey = SqliteHuey("myapp.db"). Task: @huey.task() def send_email(to, subject): .... Enqueue: send_email("[email protected]", "Hello") — returns AsyncResult. Delayed: send_email.schedule(args=("[email protected]","Hi"), delay=60) — runs in 60s. Result: result = send_email(...). result.get(blocking=True, timeout=10). result.is_ready(). result.get(preserve=True) — keep in store. Periodic: from huey import crontab. @huey.periodic_task(crontab(minute="0", hour="8")). crontab(minute="*/5") — every 5 min. crontab(day_of_week="1-5") — weekdays. Revoke: result.revoke(). send_email.revoke_by_id(task_id). send_email.restore(task_id). Retry: @huey.task(retries=3, retry_delay=10). raise RetryTask — explicit retry. Pipeline: add.s(1, 2).then(multiply, 3) — chain results. Pre/post hooks: @huey.pre_execute() def before(task): log(task.name). Immediate mode: huey.immediate = True — execute inline for tests. Start consumer: huey_consumer.py myapp.huey -w 4 -k process. -k thread for thread workers. -k greenlet for gevent. Claude Code generates Huey task definitions, periodic schedules, and consumer configuration.

CLAUDE.md for Huey

## Huey Stack
- Version: huey >= 2.5 | pip install "huey[redis]" or huey[sqlite]
- Backend: RedisHuey("app", host="localhost") | SqliteHuey("jobs.db")
- Task: @huey.task() def fn(*args): ... → fn(*args) returns AsyncResult
- Periodic: @huey.periodic_task(crontab(minute="*/15")) — no args
- Result: result.get(blocking=True, timeout=10) | result.is_ready()
- Retry: @huey.task(retries=3, retry_delay=30) | raise RetryTask in body
- Test: huey.immediate = True — runs tasks synchronously inline

Huey Task Queue Pipeline

# app/tasks.py — Huey task definitions, periodic jobs, and result handling
from __future__ import annotations

import logging
import os
import time
from datetime import datetime, timezone
from typing import Any

from huey import RedisHuey, SqliteHuey, crontab
from huey.exceptions import RetryTask

log = logging.getLogger(__name__)

# ─────────────────────────────────────────────────────────────────────────────
# Huey instance — choose backend from environment
# ─────────────────────────────────────────────────────────────────────────────

def _make_huey():
    backend = os.environ.get("HUEY_BACKEND", "sqlite")
    if backend == "redis":
        return RedisHuey(
            "myapp",
            host=os.environ.get("REDIS_HOST", "localhost"),
            port=int(os.environ.get("REDIS_PORT", "6379")),
            db=int(os.environ.get("REDIS_DB", "0")),
            results=True,
            store_none=False,
        )
    # Default: SQLite — good for single-machine deployments
    return SqliteHuey(
        os.environ.get("HUEY_DB", "huey_tasks.db"),
        results=True,
    )


huey = _make_huey()


# ─────────────────────────────────────────────────────────────────────────────
# 1. Basic async tasks
# ─────────────────────────────────────────────────────────────────────────────

@huey.task()
def send_email(to: str, subject: str, body: str = "") -> dict:
    """
    Enqueue: result = send_email("[email protected]", "Welcome")
    Result:  result.get(blocking=True, timeout=30)
    """
    log.info("send_email", extra={"to": to, "subject": subject})
    time.sleep(0.1)   # simulate SMTP call
    return {"sent": True, "to": to, "timestamp": datetime.now(timezone.utc).isoformat()}


@huey.task()
def resize_image(image_id: int, width: int, height: int) -> dict:
    """CPU-bound task — runs in a worker process."""
    log.info("resize_image", extra={"id": image_id, "size": f"{width}x{height}"})
    time.sleep(0.2)   # simulate image processing
    return {"image_id": image_id, "new_path": f"/processed/{image_id}_{width}x{height}.jpg"}


@huey.task()
def export_report(user_id: int, format: str = "csv") -> str:
    """Long-running task that returns a file path."""
    time.sleep(0.5)
    path = f"/tmp/reports/user_{user_id}_{format}_{int(time.time())}.{format}"
    return path


# ─────────────────────────────────────────────────────────────────────────────
# 2. Retrying tasks — transient failures
# ─────────────────────────────────────────────────────────────────────────────

@huey.task(retries=3, retry_delay=10)
def call_external_api(endpoint: str, payload: dict) -> dict:
    """
    Automatically retried up to 3 times with 10s delay on any exception.
    Raise RetryTask explicitly for controlled retry (e.g., rate limit 429).
    """
    log.info("call_external_api", extra={"endpoint": endpoint})
    # Simulate occasional 429 rate limit
    import random
    if random.random() < 0.3:
        log.warning("rate_limited", extra={"endpoint": endpoint})
        raise RetryTask    # explicit retry — does not count against retries limit
    time.sleep(0.05)
    return {"endpoint": endpoint, "status": 200, "data": payload}


@huey.task(retries=5, retry_delay=30)
def sync_inventory(product_id: int) -> dict:
    """
    Retry with exponential back-off via retry_delay (fixed in Huey).
    For exponential back-off, raise RetryTask with a calculated delay:
        raise RetryTask(eta=datetime.now() + timedelta(seconds=2**attempt))
    """
    log.info("sync_inventory", extra={"product_id": product_id})
    time.sleep(0.02)
    return {"product_id": product_id, "stock": 100, "synced": True}


# ─────────────────────────────────────────────────────────────────────────────
# 3. Periodic tasks — cron schedule
# ─────────────────────────────────────────────────────────────────────────────

@huey.periodic_task(crontab(minute="0", hour="8", day_of_week="1-5"))
def send_daily_digest() -> None:
    """Runs Mon–Fri at 08:00. Periodic tasks take no arguments."""
    log.info("send_daily_digest")
    print(f"[{datetime.now().isoformat()}] Sending daily digest")


@huey.periodic_task(crontab(minute="*/15"))
def cleanup_temp_files() -> None:
    """Runs every 15 minutes."""
    log.info("cleanup_temp_files")
    # os.path.glob("/tmp/reports/*.tmp") and delete old files


@huey.periodic_task(crontab(minute="0", hour="*/4"))
def sync_all_inventory() -> None:
    """Runs every 4 hours — fan out to per-product tasks."""
    product_ids = [1, 2, 3, 4, 5]   # in production: query DB
    for pid in product_ids:
        sync_inventory(pid)          # enqueue individual tasks


@huey.periodic_task(crontab(minute="0", hour="0", day="1"))
def generate_monthly_report() -> None:
    """First day of each month at midnight."""
    log.info("generate_monthly_report")
    export_report(user_id=0, format="csv")


# ─────────────────────────────────────────────────────────────────────────────
# 4. Delayed / scheduled execution
# ─────────────────────────────────────────────────────────────────────────────

def schedule_welcome_email(user_id: int, email: str, delay_seconds: int = 300) -> Any:
    """
    .schedule(args=..., delay=N) enqueues the task to run after N seconds.
    Returns an AsyncResult — can still .revoke() before it fires.
    """
    return send_email.schedule(
        args=(email, "Welcome to the platform!"),
        kwargs={"body": f"Hi, your user ID is {user_id}."},
        delay=delay_seconds,
    )


# ─────────────────────────────────────────────────────────────────────────────
# 5. Pre/post execute hooks — cross-cutting middleware
# ─────────────────────────────────────────────────────────────────────────────

@huey.pre_execute()
def log_task_start(task) -> None:
    """Runs before every task — useful for tracing, auth checks."""
    log.debug("task_start", extra={"task": task.name, "id": task.id})


@huey.post_execute()
def log_task_end(task, task_value, exc) -> None:
    """Runs after every task — task_value is the return value, exc is any exception."""
    if exc:
        log.error("task_failed", extra={"task": task.name, "error": str(exc)})
    else:
        log.debug("task_done", extra={"task": task.name})


# ─────────────────────────────────────────────────────────────────────────────
# 6. Task pipeline — chaining
# ─────────────────────────────────────────────────────────────────────────────

@huey.task()
def validate_upload(file_path: str) -> str:
    """Step 1: validate uploaded file, return path."""
    time.sleep(0.05)
    return file_path


@huey.task()
def process_upload(file_path: str) -> str:
    """Step 2: process the file, return output path."""
    time.sleep(0.1)
    return file_path.replace("uploads", "processed")


@huey.task()
def notify_upload_done(output_path: str) -> dict:
    """Step 3: notify user that processing is complete."""
    return {"done": True, "path": output_path}


def chain_upload_pipeline(file_path: str):
    """
    Pipeline: each task's return value is passed as the first arg of the next.
    Executed in sequence by the consumer — not in parallel.
    """
    return (
        validate_upload.s(file_path)
        .then(process_upload)
        .then(notify_upload_done)
    )


# ─────────────────────────────────────────────────────────────────────────────
# 7. Immediate mode — synchronous execution for tests
# ─────────────────────────────────────────────────────────────────────────────

def run_tests_demo() -> None:
    """
    huey.immediate = True causes all tasks to execute synchronously
    in the calling thread — no consumer process needed for tests.
    """
    huey.immediate = True
    try:
        result = send_email("[email protected]", "Test")
        # In immediate mode .get() returns the value directly
        value = result()
        print(f"Immediate result: {value}")

        img_result = resize_image(42, 800, 600)
        print(f"Resize result: {img_result()}")

    finally:
        huey.immediate = False


# ─────────────────────────────────────────────────────────────────────────────
# 8. FastAPI integration
# ─────────────────────────────────────────────────────────────────────────────

try:
    from fastapi import FastAPI, HTTPException
    from pydantic import BaseModel

    app = FastAPI()

    class EmailRequest(BaseModel):
        to: str
        subject: str
        body: str = ""

    class ImageRequest(BaseModel):
        image_id: int
        width: int
        height: int

    @app.post("/tasks/email")
    async def enqueue_email(req: EmailRequest) -> dict:
        result = send_email(req.to, req.subject, req.body)
        return {"task_id": result.id, "status": "queued"}

    @app.post("/tasks/resize")
    async def enqueue_resize(req: ImageRequest) -> dict:
        result = resize_image(req.image_id, req.width, req.height)
        return {"task_id": result.id, "status": "queued"}

    @app.get("/tasks/{task_id}")
    async def get_task_result(task_id: str) -> dict:
        result = huey.result(task_id)
        if result is None:
            return {"task_id": task_id, "status": "pending"}
        return {"task_id": task_id, "status": "done", "result": result}

    @app.delete("/tasks/{task_id}")
    async def revoke_task(task_id: str) -> dict:
        huey.revoke_by_id(task_id)
        return {"task_id": task_id, "status": "revoked"}

except ImportError:
    app = None  # type: ignore[assignment]


# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    print("=== Immediate mode demo ===")
    run_tests_demo()

    print("\n=== Enqueue tasks (requires consumer) ===")
    r1 = send_email("[email protected]", "Hello", "World")
    r2 = resize_image(1, 1920, 1080)
    print(f"Enqueued: email={r1.id}  resize={r2.id}")

    print("\n=== Scheduled task ===")
    r3 = schedule_welcome_email(99, "[email protected]", delay_seconds=30)
    print(f"Scheduled in 30s: {r3.id}")
    r3.revoke()
    print("Revoked scheduled task.")

For the Celery alternative — Celery requires a broker (Redis or RabbitMQ), a result backend, a CELERY_ settings module, at least three running processes (broker, worker, beat), and ~500ms startup time per worker, while Huey runs with a single huey_consumer.py myapp.tasks.huey command against Redis or SQLite, zero configuration files, and a huey.immediate = True flag that makes all tasks run synchronously in tests without any mocking. For the rq (Redis Queue) alternative — rq requires Redis exclusively and surfaces a separate rqscheduler process for cron jobs, while Huey’s @huey.periodic_task(crontab(...)) decorator bakes the schedule directly into the task definition and the single consumer process handles both on-demand and periodic tasks without a separate scheduler daemon — and Huey’s SQLite backend means zero external dependencies for development and single-machine deployments. The Claude Skills 360 bundle includes Huey skill sets covering RedisHuey and SqliteHuey backend configuration, @huey.task with retries and retry_delay, RetryTask for controlled retry logic, @huey.periodic_task with crontab expressions, task.schedule for delayed execution, AsyncResult.get blocking result retrieval, revoke and restore for task cancellation, pre_execute and post_execute hooks, pipeline chaining with .then(), huey.immediate mode for test isolation, and FastAPI /tasks endpoint integration. Start with the free tier to try lightweight task queue code generation.

Keep Reading

AI

Claude Code for email.contentmanager: Python Email Content Accessors

Read and write EmailMessage body content with Python's email.contentmanager module and Claude Code — email contentmanager ContentManager for the class that maps content types to get and set handler functions allowing EmailMessage to support get_content and set_content with type-specific behaviour, email contentmanager raw_data_manager for the ContentManager instance that handles raw bytes and str payloads without any conversion, email contentmanager content_manager for the standard ContentManager instance used by email.policy.default that intelligently handles text plain text html multipart and binary content types, email contentmanager get_content_text for the handler that returns the decoded text payload of a text-star message part as a str, email contentmanager get_content_binary for the handler that returns the raw decoded bytes payload of a non-text message part, email contentmanager get_data_manager for the get-handler lookup used by EmailMessage get_content to find the right reader function for the content type, email contentmanager set_content text for the handler that creates and sets a text part correctly choosing charset and transfer encoding, email contentmanager set_content bytes for the handler that creates and sets a binary part with base64 encoding and optional filename Content-Disposition, email contentmanager EmailMessage get_content for the method that reads the message body using the registered content manager handlers, email contentmanager EmailMessage set_content for the method that sets the message body and MIME headers in one call, email contentmanager EmailMessage make_alternative make_mixed make_related for the methods that convert a simple message into a multipart container, email contentmanager EmailMessage add_attachment for the method that attaches a file or bytes to a multipart message, and email contentmanager integration with email.message and email.policy and email.mime and io for building high-level email readers attachment extractors text body accessors HTML readers and policy-aware MIME construction pipelines.

5 min read Feb 12, 2029
AI

Claude Code for email.charset: Python Email Charset Encoding

Control header and body encoding for international email with Python's email.charset module and Claude Code — email charset Charset for the class that wraps a character set name with the encoding rules for header encoding and body encoding describing how to encode text for that charset in email messages, email charset Charset header_encoding for the attribute specifying whether headers using this charset should use QP quoted-printable encoding BASE64 encoding or no encoding, email charset Charset body_encoding for the attribute specifying the Content-Transfer-Encoding to use for message bodies in this charset such as QP or BASE64, email charset Charset output_codec for the attribute giving the Python codec name used to encode the string to bytes for the wire format, email charset Charset input_codec for the attribute giving the Python codec name used to decode incoming bytes to str, email charset Charset get_output_charset for returning the output charset name, email charset Charset header_encode for encoding a header string using the charset's header_encoding method, email charset Charset body_encode for encoding body content using the charset's body_encoding, email charset Charset convert for converting a string from the input_codec to the output_codec, email charset add_charset for registering a new charset with custom encoding rules in the global charset registry, email charset add_alias for adding an alias name that maps to an existing registered charset, email charset add_codec for registering a codec name mapping for use by the charset machinery, and email charset integration with email.message and email.mime and email.policy and email.encoders for building international email senders non-ASCII header encoders Content-Transfer-Encoding selectors charset-aware message constructors and MIME encoding pipelines.

5 min read Feb 11, 2029
AI

Claude Code for email.utils: Python Email Address and Header Utilities

Parse and format RFC 2822 email addresses and dates with Python's email.utils module and Claude Code — email utils parseaddr for splitting a display-name plus angle-bracket address string into a realname and email address tuple, email utils formataddr for combining a realname and address string into a properly quoted RFC 2822 address with angle brackets, email utils getaddresses for parsing a list of raw address header strings each potentially containing multiple comma-separated addresses into a list of realname address tuples, email utils parsedate for parsing an RFC 2822 date string into a nine-tuple compatible with time.mktime, email utils parsedate_tz for parsing an RFC 2822 date string into a ten-tuple that includes the UTC offset timezone in seconds, email utils parsedate_to_datetime for parsing an RFC 2822 date string into an aware datetime object with timezone, email utils formatdate for formatting a POSIX timestamp or the current time as an RFC 2822 date string with optional usegmt and localtime flags, email utils format_datetime for formatting a datetime object as an RFC 2822 date string, email utils make_msgid for generating a globally unique Message-ID string with optional idstring and domain components, email utils decode_rfc2231 for decoding an RFC 2231 encoded parameter value into a tuple of charset language and value, email utils encode_rfc2231 for encoding a string as an RFC 2231 encoded parameter value, email utils collapse_rfc2231_value for collapsing a decoded RFC 2231 tuple to a Unicode string, and email utils integration with email.message and email.headerregistry and datetime and time for building address parsers date formatters message-id generators header extractors and RFC-compliant email construction utilities.

5 min read Feb 10, 2029

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free