A better job queue with Temporal Standalone Activities

AUTHORS
Phil Prasek, Hien Phan
PUBLISHED
Sep 21, 2026
CATEGORY
DURATION
8 MIN
  • Python
  • Durable Execution
  • Temporal Primitives

Say a customer orders a pair of shoes online. When the package ships, your fulfillment application needs to notify the retailer’s order-management system through a webhook. You queue the webhook so your application can continue without waiting for a response. A Worker picks up the job and sends the webhook later.

Getting the job to a Worker is only the first part. You still need one place to see whether the job is waiting, running, completed, or failed, and whether it will be retried. The queue alone does not provide that record, so you have to build status records, retry logic, monitoring, and recovery tools. Together, those pieces become a custom job system your team must maintain. If the job stalls, the customer may never see that their order shipped. Your team scrambles to reconstruct what happened across those systems and decide how to recover it.

Standalone Activities are Temporal’s job queue. Today, we are making them Generally Available, with support across Go, Python, Java, TypeScript, .NET, and Ruby. Standalone Activities give each background job a durable record of execution, from submission to outcome. Retries, visibility, and control are built into Temporal, so your team does not have to build and maintain a custom system around a queue.

In this example, the Activity is the function that sends the webhook. A Standalone Activity lets your application invoke it as a durable job on a Worker, without restructuring the function to fit a framework.

from dataclasses import dataclass

from temporalio import activity

@dataclass
class ShipmentUpdateInput:
    order_id: str
    status: str
    update_id: str

@activity.defn
async def send_webhook(input: ShipmentUpdateInput) -> str:
    result = await webhook_service.send(
        order_id=input.order_id,
        status=input.status,
        update_id=input.update_id,
    )
    return result.delivery_id

Start it as a job with one call:

from datetime import timedelta

handle = await client.start_activity(
    send_webhook,
    args=[
        ShipmentUpdateInput(
            order_id="ORDER-123",
            status="shipped",
            update_id="shipment-update-ORDER-123",
        )
    ],
    id="shipment-webhook-ORDER-123",
    task_queue="webhooks",
    start_to_close_timeout=timedelta(seconds=30),
)

You still write the Activity code, make its side effects safe to retry, and run the Workers.

The job remains recorded through execution and afterward#

Once you start the webhook delivery job as a Standalone Activity, Temporal creates a durable record, called an Activity Execution, before making the Task available to a Worker. The record persists through Worker crashes, restarts, and deployments. If an attempt fails or times out, Temporal schedules another attempt when the execution’s timeouts and Retry Policy allow.

A long-running job can still be one Activity Execution. For example, an ETL job processing 1,000 files can send heartbeats as it works and record its latest checkpoint. If the heartbeats stop, the Heartbeat Timeout lets Temporal detect the failure quickly. On retry, the Activity code can use that checkpoint to resume instead of starting over.

After the execution closes, Temporal retains its record for the Namespace’s retention period. In Temporal Cloud, that period is 30 days by default. This gives your team time to retrieve the result or investigate a failure.

Temporal uses the Activity ID to make sure that only one Activity Execution with that ID is open at a time. If your application submits the same ID while the execution is still open, the Conflict Policy can reject the new request or use the existing execution. After the execution closes, the Reuse Policy determines whether that ID can be used again while its record is retained. These policies govern new start requests. Retries within the same Activity Execution can still produce multiple attempts.

For example, the order-management system may accept the webhook, but the Worker could crash before reporting completion to Temporal. After that attempt times out, Temporal may run the Activity function again. That is at-least-once execution. For this webhook, you could send a stable update ID that the order-management system uses to deduplicate the update.

Temporal keeps the job durable across attempts. You make the action it performs safe to retry.

Schedule a one-time job for later#

The same shipment can also trigger a job for later, such as reminding the customer on the day the package is due to arrive. With Start Delay, you submit the reminder job when the package ships and tell Temporal how long to wait before making it available to a Worker. Temporal records the job immediately, so it remains durable and visible while it waits. You do not need a separate scheduler to submit it later.

Find the job, see what happened, and act on it#

Now suppose the customer who ordered the shoes still sees “Preparing to ship” after the package has left the warehouse. When the customer contacts support, your team needs to find the webhook job and understand why the update has not arrived. Its Activity Execution gives you one place to do that.

Add the order ID as a Search Attribute when you start the job. Your team can then search that ID to find the webhook job. The Temporal UI shows the job’s status, retry count, and last error. You can retrieve the result through the CLI, SDK, or API.

You can cancel, terminate, and delete jobs individually. Additional operator commands, now available in Public Preview, let you individually pause, unpause, or reset an execution; update its options; reschedule a delayed start; or have a Worker run it now. Batch operator commands are also in Public Preview for cancel, terminate, and delete, with more on the way! If the shipment update does not arrive, your team can quickly find the job, diagnose the problem, and act without reconstructing the job’s history across separate systems.

Share Worker capacity without losing control#

Now imagine the same retailer processing thousands of shipment updates across several fulfillment centers. One Worker pool may handle all of them. An urgent correction to the customer’s shoe order should not wait behind routine updates. A surge from one fulfillment center should not crowd out updates from the others, either.

Standalone Activities let you control how jobs share that Worker capacity. Priority helps dispatch higher-priority jobs before lower-priority jobs as capacity becomes available. Sustained higher-priority load can keep lower-priority jobs waiting.

Within the same priority level, optional, best-effort weighted Fairness can distribute dispatches among fulfillment centers on a best-effort basis. This can reduce the need for a separate queue and Worker pool for each center. Fairness is priced separately in Temporal Cloud.

Start with one job and grow without starting over#

An Activity Execution can run for a long time and process many items while remaining one job. A Workflow becomes appropriate when the application needs to coordinate distinct steps, waits, or decisions.

The webhook delivery, for example, may later become one step in a larger process. TThat process could wait for confirmation that the order-management system applied the shipment update and alert support if no confirmation arrives. If no confirmation arrives, the process could alert support. A Temporal Workflow can coordinate those steps using the existing Activity on the same Workers to send the update. You can write and deploy your Activity Workers once, then invoke the Activity either as a Standalone Activity or as a step in a Workflow.

Teams can also adopt Standalone Activities one job type at a time instead of replacing an existing job platform all at once. In a joint webinar with Temporal, Coinbase reported that its existing Background Jobs Service processes 200 million to 600 million jobs a day across 186 namespaces. Since Public Preview, Coinbase has completed the first phase of its migration to Standalone Activities, moving 17 namespaces and about 25 percent of its background-job traffic with zero downtime and zero job loss. It has also stopped onboarding new workloads to the legacy service, so new background jobs start on Standalone Activities.

Get started with Standalone Activities#

You do not need to start at Coinbase scale. Standalone Activities are generally available in Temporal Cloud and self-hosted deployments.

Planned work includes direct support for Temporal Schedules that start Standalone Activities, audit exports, the ability to start Standalone Activities through Nexus, and enhanced manual completion.

The shipment webhook is one example. Other applications might use a Standalone Activity to execute a payout, run a compliance check, provision access, deliver a notification, or complete an agent action. In each case, the problem has the same shape: the application hands off one background action but still depends on it reaching a known outcome. The job must remain recorded through Worker failures and retries so your team can find it, understand what happened, and act on it.

Choose your SDK and follow the Standalone Activities quickstart. Start with one job your application depends on. When you are ready, add the next.

Temporal Cloud

Ready to see for yourself?

Sign up for Temporal Cloud today and get $150 in free credits.

Build invincible applications

It sounds like magic, we promise it's not.