Skip to content
cccskills
FreePublished on GitHubEnglish overview

upstash-workflow

Build asynchronous workflows with Upstash Workflow and QStash using a staged design: preview work, paginate and fan out large batches, then process one item per run. The guide also covers flow control, retries, and deployment setup.

OriginalShow the original description

Use for Upstash Workflow/QStash handlers, triggers, durable steps and async fan-out.

lobehub/lobehub83,502 stars(GitHub 83,502 + cccskills 0)

Run score Not tested

See how to install

Good for

  • Design a workflow that previews work before execution
  • Split a large batch into paginated, parallel tasks
  • Implement a handler that processes one item per run
  • Configure QStash flow control and workflow routes

Overview

What it does

This guide helps structure asynchronous workflows built with Upstash Workflow and QStash. It separates work into three layers: an entry point that checks prerequisites, counts eligible items, filters existing items, and supports dry runs; a pagination layer that divides large batches and fans work out; and an execution layer that handles one item per run. It also covers flow control, unique step names, payload validation, logging, error handling, tests, and cloud deployment references.

The patterns are designed around rate limits, workflow step limits, and retry safety. A dry run reports what would be processed without triggering side effects. Fan-out divides oversized batches into chunks, while idempotency helps avoid processing the same item twice after a retry. Parallelism and request rates can be set through flowControl.

When it helps

Use this guide when adding background processing for many items or reviewing how an existing workflow splits work, controls concurrency, and previews the expected work. It is intended for implementers building applications that use Upstash Workflow and QStash.

Example requests

  • “Design this batch job with a dry run, pagination, and one-item executions.”
  • “Outline how to add a QStash handler and configure flowControl.”

Notes

Every workflow requires APP_URL and QSTASH_TOKEN. Set QSTASH_URL when using a custom QStash URL.

This overview was written by AI (OpenAI Codex) from the public SKILL.md. Check the original below for the exact behavior.

Document check

AI checked the SKILL.md for operations that need care and for setup requirements. The score comes only from actually running the skill (hands-on test).

SafetyAre sending data, deleting files, and running commands disclosed?
AGoodIt specifies dry runs, small-batch testing, and idempotency for retries.
Easy setupDoes it need few tools or API keys, and are they documented?
BPartly lackingIt names required `APP_URL` and `QSTASH_TOKEN` but gives no setup steps for them.

Not counted in the score. Rated by AI (OpenAI Codex) as of Oct 26, 2026. Treat it as a guide and read the original before installing.

Disagree? Request a re-evaluation

Tell us which point is wrong and why. No login needed. We will check it against the SKILL.md, redo the evaluation, and show the result here.

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

Files included (5)

  • SKILL.md6.8 KB
  • references/best-practices.md6.5 KB
  • references/cloud.md5.9 KB
  • references/examples.md6.5 KB
  • references/implementation.md9.7 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Upstash Workflow Implementation Guide

Standard patterns for implementing Upstash Workflow + QStash async workflows in the LobeHub codebase.

🎯 The Three Core Patterns

Every workflow in LobeHub combines these three patterns. They exist because the platform constrains you in three ways: rate limits make blind fan-out dangerous, step limits cap a single workflow's size, and idempotency demands that retries don't double-process.

  1. 🔍 Dry-Run Mode — get statistics without triggering actual execution
  2. 🌟 Fan-Out Pattern — split large batches into smaller chunks for parallel processing
  3. 🎯 Single Task Execution — each workflow execution processes exactly ONE item

Architecture Overview

All workflows follow the same 3-layer architecture:

Layer 1: Entry Point (process-*)
  ├─ Validates prerequisites
  ├─ Calculates total items to process
  ├─ Filters existing items
  ├─ Supports dry-run mode (statistics only)
  └─ Triggers Layer 2 if work is needed

Layer 2: Pagination (paginate-*)
  ├─ Handles cursor-based pagination
  ├─ Implements fan-out for large batches
  ├─ Recursively processes all pages
  └─ Triggers Layer 3 for each item

Layer 3: Single Task Execution (execute-* / generate-*)
  └─ Performs actual business logic for ONE item

Real examples in this codebase: topicAutoSummary, agentEvalRun — see references/examples.md.


The Three Patterns in 60 Seconds

1. Dry-Run Mode

Short-circuit Layer 1 before any side effects so callers can preview what would happen:

if (dryRun) {
  return {
    ...result,
    dryRun: true,
    message: `[DryRun] Would process ${itemsNeedingProcessing.length} items`,
  };
}

Use case: check how many items will be processed before committing.

2. Fan-Out Pattern

Layer 2 splits oversized batches into chunks and recursively re-triggers itself with each chunk. This avoids hitting workflow step limits when one page contains too many items:

const CHUNK_SIZE = 20;

if (itemIds.length > CHUNK_SIZE) {
  const chunks = chunk(itemIds, CHUNK_SIZE);
  await Promise.all(
    chunks.map((ids, idx) =>
      context.run(`workflow:fanout:${idx + 1}/${chunks.length}`, () =>
        WorkflowClass.triggerPaginateItems({ itemIds: ids }),
      ),
    ),
  );
}

Defaults: PAGE_SIZE = 50 (items per page), CHUNK_SIZE = 20 (items per fan-out chunk).

3. Single Task Execution

Layer 3 always processes exactly one item per invocation. Parallelism comes from Layer 2 fanning out to many Layer 3 invocations, controlled by flowControl:

app.post(
  '/execute-item',
  serve<ExecutePayload>(
    async (context) => {
      const { itemId } = context.requestPayload ?? {};
      if (!itemId) return { success: false, error: 'Missing itemId' };

      const item = await context.run('workflow:get-item', () => getItem(itemId));
      const result = await context.run('workflow:execute', () => processItem(item));
      await context.run('workflow:save', () => saveResult(itemId, result));

      return { success: true, itemId, result };
    },
    {
      flowControl: { key: 'workflow.execute', parallelism: 10, ratePerSecond: 5 },
    },
  ),
);

File Structure

src/app/(backend)/api/workflows/
└── [[...route]]/route.ts             # Single catch-all — forwards every request to the Hono app below

apps/server/src/router-hono/workflows/
├── index.ts                          # Mounts each workflow's Hono app at /api/workflows/{workflow-name}
└── {workflow-name}/
    ├── index.ts                       # Hono app — one `app.post('/{layer}', serve(handler, options))` per layer
    ├── dispatch.ts / paginate-*.ts    # Layer 1 + 2 handler(s) — entry point, dry-run, pagination, fan-out
    └── execute.ts / execute-*.ts      # Layer 3 handler — single-task execution

apps/server/src/workflows/
└── {workflowName}/
    └── index.ts                       # Workflow class — static trigger*() methods that POST to the routes above

Every layer is a handler mounted on a per-workflow Hono app under apps/server/src/router-hono/workflows/; the Next.js route under src/app only dispatches into it.


Where to Go Next

Pick the reference that matches what you're doing:

You want to...Read
Write the Workflow class + 3 routes from scratchreferences/implementation.md
Tune flowControl, error handling, logging, testingreferences/best-practices.md
See two real workflows end-to-endreferences/examples.md
Deploy on lobehub-cloud (re-exports, cloud-only ops)references/cloud.md

Environment Variables

# Required for all workflows
APP_URL=https://your-app.com # Base URL for workflow endpoints
QSTASH_TOKEN=qstash_xxx      # QStash authentication token

# Optional (for custom QStash URL)
QSTASH_URL=https://custom-qstash.com

Checklist for New Workflows

Planning

  • Identify the entity to process (users, agents, items, …)
  • Define the per-item business logic
  • Determine filtering logic (Redis cache, database state, …)

Implementation

  • Define payload types with TypeScript interfaces
  • Create workflow class with static trigger methods
  • Layer 1: entry point with dry-run support
  • Layer 1: filtering logic to avoid duplicate work
  • Layer 2: pagination with fan-out
  • Layer 3: single-task execution (ONE item per run)
  • Configure appropriate flowControl for each layer
  • Consistent logging with workflow prefixes
  • Validate all required payload parameters
  • Unique context.run() step names

Quality & Deployment

  • Return consistent response shapes
  • Configure cloud deployment (references/cloud.md if on lobehub-cloud)
  • Write integration tests (dryRun path + full path)
  • Smoke-test with dry-run first
  • Test with a small batch before full rollout

Additional Resources

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

acceptance

FreeSummary

Use this skill to verify a delivery by exercising the real product through a suitable surface such as a CLI, web app, desktop app, or iOS Simulator. It helps create or find a verification plan, capture evidence, and publish an acceptance report.

  • Verifying a completed product change
  • Collecting screenshots or other evidence
  • Creating a verification plan and report
lobehub/lobehub83.5KUpdated Oct 26, 2026

Use this skill to add an AI model provider to LobeHub across runtime integration, model cards, settings, branding, documentation, and acceptance checks. It also covers provider documentation updates and distinguishes new providers from models added to an existing provider.

  • Integrating a new AI model provider into LobeHub
  • Updating setup or usage documentation for a provider
  • Checking whether a model needs a new provider integration
lobehub/lobehub83.5KUpdated Oct 26, 2026

add-setting-env

FreeSummary

Use this skill to add a server-side environment variable that sets a default for a user setting. It walks through validation, server configuration and store merging, plus updating the example environment file and self-hosting documentation.

  • Adding an environment variable for a setting default
  • Wiring a new setting domain into server config
  • Documenting a new variable for self-hosting
lobehub/lobehub83.5KUpdated Oct 26, 2026

Provides guidance for registering hooks around an agent’s execution steps, tool calls, human approvals, context compression, and sub-agent calls. Hooks can observe events, supply local mock tool results, or use webhooks to allow or deny tool results under configured policies.

  • Observing agent steps and tool errors
  • Mocking tool results during local execution
  • Requiring webhook decisions before or after a tool call
lobehub/lobehub83.5KUpdated Oct 26, 2026

agent-signal

FreeSummary

Build event-driven background workflows for agents by defining sources, interpreting them as signals, and running actions through policies. It also guides asynchronous handoffs, deduplication, scoped execution, completion receipts, and observability.

  • Adding a new event source to an agent workflow
  • Routing interpreted signals to concrete background actions
  • Enqueuing work for asynchronous processing
lobehub/lobehub83.5KUpdated Oct 26, 2026

Use this skill to run end-to-end acceptance checks for bot channels in real desktop chat apps. It drives apps such as Discord, Slack, Telegram, WeChat, Lark, and QQ to send a message, wait for a response, and capture the result.

  • Checking a bot response in a real Discord channel
  • Testing chat behavior through Slack or Telegram
  • Capturing a bot interaction in a native macOS app
lobehub/lobehub83.5KUpdated Oct 26, 2026

See all skills by lobehub

Report a problem with this skill