Skip to main content
skill Claude Code CX Codex Cursor

python-background-jobs — Claude Code skill: background jobs

This skill shows how to move long-running Python work out of request handling and into workers. Use it for queues, exports, notifications, and event-driven flows.

Install into Claude Code · Plugin marketplace All methods and platforms ↓
/plugin marketplace add wshobson/agents
/plugin install python-development@claude-code-workflows
Open on GitHub

What python-background-jobs does

python-background-jobs explains a task-queue flow where an API accepts work, enqueues it, and returns a job ID while a worker processes the task. Its examples use Celery and cover worker execution, job states, status polling, retries, and timeout settings.

The skill focuses on idempotent tasks because queues can deliver a job more than once. It uses Redis as the Celery broker in examples and mentions RQ, Dramatiq, AWS SQS, and GCP Tasks as alternatives. More detailed patterns are stored in references/details.md.

Install it when a Python service has long-running operations or unreliable integrations. Skip it for a small handler that should finish inside the request.

What it helps with

  • move report generation out of the request cycle
  • queue email or webhook delivery
  • retry work after a transient failure
  • track a job from pending to completion
  • prevent duplicate payment processing

Example prompts for the agent

  • Show how to run a data export as a Celery task and return a job ID.
  • Make this order-processing task idempotent and retry it on ConnectionError.
  • Design a job status endpoint with pending, running, succeeded, and failed states.

How to install python-background-jobs

1Plugin marketplace

/plugin marketplace add wshobson/agents
/plugin install python-development@claude-code-workflows

This installs the whole python-development plugin with all its skills

2Skills CLI (Vercel)

npx skills add wshobson/agents --skill python-background-jobs -a claude-code

3Manually: put the files in place

~/.claude/skills/python-background-jobs/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/python-background-jobs/

From the same set213

The whole set →
typescript-advanced-types Seth Hobson Guides an agent through advanced TypeScript types, from generics to conditional and mapped types. Use it for typed libraries, API clients, or strict configuration objects. Claude Code CX Codex Cursor 92,169installs tailwind-design-system Seth Hobson Helps build design systems with Tailwind CSS v4, from theme tokens to component variants. Use it when a project needs shared UI patterns. Claude Code CX Codex Cursor 70,180installs brand-landingpage Travis D. Elliott This skill interviews you about the product and its visual direction, then builds a landing page through Stitch. Use it when there’s no established design yet. Claude Code CX Codex Cursor 39,476installs python-testing-patterns Seth Hobson This skill guides Python testing with pytest, fixtures and mocks. Use it when building a test suite or tracking down failing checks. Claude Code CX Codex Cursor 36,943installs python-performance-optimization Seth Hobson This skill profiles Python code to locate CPU and memory bottlenecks. Use it when an application responds slowly or consumes too many resources. Claude Code CX Codex Cursor 35,675installs nextjs-app-router-patterns Seth Hobson This skill covers Next.js App Router patterns for rendering, routing, and data fetching. Use it when starting an App Router project or moving from Pages Router. Claude Code CX Codex Cursor 32,529installs api-design-principles Seth Hobson Use this skill to plan or review REST and GraphQL APIs. It helps when writing a specification or setting API conventions for a team. Claude Code CX Codex Cursor 30,348installs code-review-excellence Seth Hobson This skill guides pull request reviews, catches logic and security issues, and helps teams give specific feedback. Use it for review standards or developer mentoring. Claude Code CX Codex Cursor 30,193installs

Similar

developing-genkit-python official google A skill for building Genkit apps in Python: generation, streaming, tools, flows and agents. Useful when your agent fumbles imports or Genkit API calls. Claude Code Gemini CLI CX Codex 3,600installs developing-genkit-js official google This skill helps build and troubleshoot Genkit AI apps in Node.js and TypeScript. Use it for flows, agents, tools, and Genkit API errors. Claude Code Gemini CLI CX Codex 3,600installs flowstudio-power-automate-mcp official github Connects GitHub Copilot to Power Automate through FlowStudio MCP, with auth setup, tool discovery, and oversized-response handling. GitHub Copilot 4,200installs mcp-builder official anthropics This skill walks through building an MCP server in TypeScript or Python, from reading the protocol spec to writing tests and evaluation questions. Claude Code Claude.ai 130,949installs google-agents-cli-adk-code official Google A reference skill for building ADK agents with tools, callbacks, state, and workflows. Use it when an agent project needs concrete API patterns or code examples. Claude Code CX Codex Cursor +1 511,400installs lark-im larksuite This skill lets an agent work with Lark IM messages, chats, files, and interactive cards. Use it when coding tasks need access to team conversations. Claude Code CX Codex Cursor +1 472,300installs lark-event larksuite Listens to Lark/Feishu events and streams them as NDJSON. Use it for bots, message processing, and long-running subscribers. Claude Code CX Codex Cursor +1 466,200installs caveman-discover JuliusBrussee Finds and labels every LLM workflow in your repository so Caveman Cloud breaks down spend by actual job rather than grouping everything into one bucket. Claude Code CX Codex Cursor +1 103,500installs

Questions about python-background-jobs

How do I install python-background-jobs in Claude Code?

Run npx skills add wshobson/agents --skill python-background-jobs -a claude-code. The skill file is placed at ~/.claude/skills/python-background-jobs/SKILL.md.

What does python-background-jobs do?

It provides Python patterns for task queues, background workers, retries, and event-driven processing. The API can return a job ID while the worker handles the operation.

Does python-background-jobs require Redis?

Redis is the broker used in the Celery examples. The skill also names RQ, Dramatiq, AWS SQS, and GCP Tasks as alternative queue choices.

Source text

SKILL.md · MIT
---
name: python-background-jobs
description: Python background job patterns including task queues, workers, and event-driven architecture. Use when implementing async task processing, job queues, long-running operations, or decoupling work from request/response cycles.
---

# Python Background Jobs & Task Queues

Decouple long-running or unreliable work from request/response cycles. Return immediately to the user while background workers handle the heavy lifting asynchronously.

## When to Use This Skill

- Processing tasks that take longer than a few seconds
- Sending emails, notifications, or webhooks
- Generating reports or exporting data
- Processing uploads or media transformations
- Integrating with unreliable external services
- Building event-driven architectures

## Core Concepts

### 1. Task Queue Pattern

API accepts request, enqueues a job, returns immediately with a job ID. Workers process jobs asynchronously.

### 2. Idempotency

Tasks may be retried on failure. Design for safe re-execution.

### 3. Job State Machine

Jobs transition through states: pending → running → succeeded/failed.

### 4. At-Least-Once Delivery

Most queues guarantee at-least-once delivery. Your code must handle duplicates.

## Quick Start

This skill uses Celery for examples, a widely adopted task queue. Alternatives like RQ, Dramatiq, and cloud-native solutions (AWS SQS, GCP Tasks) are equally valid choices.

```python
from celery import Celery

app = Celery("tasks", broker="redis://localhost:6379")

@app.task
def send_email(to: str, subject: str, body: str) -> None:
    # This runs in a background worker
    email_client.send(to, subject, body)

# In your API handler
send_email.delay("[email protected]", "Welcome!", "Thanks for signing up")
```

## Fundamental Patterns

### Pattern 1: Return Job ID Immediately

For operations exceeding a few seconds, return a job ID and process asynchronously.

```python
from uuid import uuid4
from dataclasses import dataclass
from enum import Enum
from datetime import datetime

class JobStatus(Enum):
    PENDING = "pending"
    RUNNING = "running"
    SUCCEEDED = "succeeded"
    FAILED = "failed"

@dataclass
class Job:
    id: str
    status: JobStatus
    created_at: datetime
    started_at: datetime | None = None
    completed_at: datetime | None = None
    result: dict | None = None
    error: str | None = None

# API endpoint
async def start_export(request: ExportRequest) -> JobResponse:
    """Start export job and return job ID."""
    job_id = str(uuid4())

    # Persist job record
    await jobs_repo.create(Job(
        id=job_id,
        status=JobStatus.PENDING,
        created_at=datetime.utcnow(),
    ))

    # Enqueue task for background processing
    await task_queue.enqueue(
        "export_data",
        job_id=job_id,
        params=request.model_dump(),
    )

    # Return immediately with job ID
    return JobResponse(
        job_id=job_id,
        status="pending",
        poll_url=f"/jobs/{job_id}",
    )
```

### Pattern 2: Celery Task Configuration

Configure Celery tasks with proper retry and timeout settings.

```python
from celery import Celery

app = Celery("tasks", broker="redis://localhost:6379")

# Global configuration
app.conf.update(
    task_time_limit=3600,          # Hard limit: 1 hour
    task_soft_time_limit=3000,      # Soft limit: 50 minutes
    task_acks_late=True,            # Acknowledge after completion
    task_reject_on_worker_lost=True,
    worker_prefetch_multiplier=1,   # Don't prefetch too many tasks
)

@app.task(
    bind=True,
    max_retries=3,
    default_retry_delay=60,
    autoretry_for=(ConnectionError, TimeoutError),
)
def process_payment(self, payment_id: str) -> dict:
    """Process payment with automatic retry on transient errors."""
    try:
        result = payment_gateway.charge(payment_id)
        return {"status": "success", "transaction_id": result.id}
    except PaymentDeclinedError as e:
        # Don't retry permanent failures
        return {"status": "declined", "reason": str(e)}
    except TransientError as e:
        # Retry with exponential backoff
        raise self.retry(exc=e, countdown=2 ** self.request.retries * 60)
```

### Pattern 3: Make Tasks Idempotent

Workers may retry on crash or timeout. Design for safe re-execution.

```python
@app.task(bind=True)
def process_order(self, order_id: str) -> None:
    """Process order idempotently."""
    order = orders_repo.get(order_id)

    # Already processed? Return early
    if order.status == OrderStatus.COMPLETED:
        logger.info("Order already processed", order_id=order_id)
        return

    # Already in progress? Check if we should continue
    if order.status == OrderStatus.PROCESSING:
        # Use idempotency key to avoid double-charging
        pass

    # Process with idempotency key
    result = payment_provider.charge(
        amount=order.total,
        idempotency_key=f"order-{order_id}",  # Critical!
    )

    orders_repo.update(order_id, status=OrderStatus.COMPLETED)
```

**Idempotency Strategies:**

1. **Check-before-write**: Verify state before action
2. **Idempotency keys**: Use unique tokens with external services
3. **Upsert patterns**: `INSERT ... ON CONFLICT UPDATE`
4. **Deduplication window**: Track processed IDs for N hours

### Pattern 4: Job State Management

Persist job state transitions for visibility and debugging.

```python
class JobRepository:
    """Repository for managing job state."""

    async def create(self, job: Job) -> Job:
        """Create new job record."""
        await self._db.execute(
            """INSERT INTO jobs (id, status, created_at)
               VALUES ($1, $2, $3)""",
            job.id, job.status.value, job.created_at,
        )
        return job

    async def update_status(
        self,
        job_id: str,
        status: JobStatus,
        **fields,
    ) -> None:
        """Update job status with timestamp."""
        updates = {"status": status.value, **fields}

        if status == JobStatus.RUNNING:
            updates["started_at"] = datetime.utcnow()
        elif status in (JobStatus.SUCCEEDED, JobStatus.FAILED):
            updates["completed_at"] = datetime.utcnow()

        await self._db.execute(
            "UPDATE jobs SET status = $1, ... WHERE id = $2",
            updates, job_id,
        )

        logger.info(
            "Job status updated",
            job_id=job_id,
            status=status.value,
        )
```

## Detailed worked examples and patterns

Detailed sections (starting with `## Advanced Patterns`) live in `references/details.md`. Read that file when the navigation summary above is insufficient.

## Best Practices Summary

1. **Return immediately** - Don't block requests for long operations
2. **Persist job state** - Enable status polling and debugging
3. **Make tasks idempotent** - Safe to retry on any failure
4. **Use idempotency keys** - For external service calls
5. **Set timeouts** - Both soft and hard limits
6. **Implement DLQ** - Capture permanently failed tasks
7. **Log transitions** - Track job state changes
8. **Retry appropriately** - Exponential backoff for transient errors
9. **Don't retry permanent failures** - Validation errors, invalid credentials
10. **Monitor queue depth** - Alert on backlog growth

© Seth Hobson · MIT · wshobson/agents

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor