zilmate 1.8.0 → 1.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/copywriting/SKILL.md +252 -0
- package/.agents/skills/copywriting/evals/evals.json +111 -0
- package/.agents/skills/copywriting/references/copy-frameworks.md +344 -0
- package/.agents/skills/copywriting/references/natural-transitions.md +272 -0
- package/.agents/skills/firecrawl-deep-research/SKILL.md +108 -0
- package/.agents/skills/shadcn/SKILL.md +267 -0
- package/.agents/skills/shadcn/agents/openai.yml +5 -0
- package/.agents/skills/shadcn/assets/shadcn-small.png +0 -0
- package/.agents/skills/shadcn/assets/shadcn.png +0 -0
- package/.agents/skills/shadcn/cli.md +290 -0
- package/.agents/skills/shadcn/customization.md +209 -0
- package/.agents/skills/shadcn/evals/evals.json +47 -0
- package/.agents/skills/shadcn/mcp.md +105 -0
- package/.agents/skills/shadcn/registry.md +277 -0
- package/.agents/skills/shadcn/rules/base-vs-radix.md +306 -0
- package/.agents/skills/shadcn/rules/composition.md +195 -0
- package/.agents/skills/shadcn/rules/forms.md +192 -0
- package/.agents/skills/shadcn/rules/icons.md +101 -0
- package/.agents/skills/shadcn/rules/styling.md +162 -0
- package/.agents/skills/tavily-research/SKILL.md +100 -0
- package/.agents/skills/upstash/SKILL.md +48 -0
- package/.agents/skills/upstash/upstash-box-js/overview.md +243 -0
- package/.agents/skills/upstash/upstash-box-py/overview.md +275 -0
- package/.agents/skills/upstash/upstash-cli/overview.md +138 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/callbacks.md +147 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/deduplication.md +86 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/dlq.md +164 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/multi-region/summary.md +388 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/multi-region/verify-multi-region-setup.ts +388 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/local-development.md +106 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/publishing-messages.md +144 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/queues-and-flow-control.md +148 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/schedules.md +177 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/url-groups.md +127 -0
- package/.agents/skills/upstash/upstash-qstash-js/overview.md +81 -0
- package/.agents/skills/upstash/upstash-qstash-js/verification/platform-specific/nextjs.md +171 -0
- package/.agents/skills/upstash/upstash-qstash-js/verification/receiver.md +213 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/algorithms.md +84 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/features.md +117 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/methods-getting-started.md +77 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/overview.md +26 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/pricing-cost.md +146 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/traffic-protection.md +77 -0
- package/.agents/skills/upstash/upstash-redis-js/advanced-features/auto-pipeline.md +49 -0
- package/.agents/skills/upstash/upstash-redis-js/advanced-features/pipeline-and-transactions.md +42 -0
- package/.agents/skills/upstash/upstash-redis-js/advanced-features/scripting.md +124 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/hashes.md +71 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/json.md +133 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/lists.md +72 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/sets.md +90 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/sorted-sets.md +126 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/streams.md +196 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/strings.md +73 -0
- package/.agents/skills/upstash/upstash-redis-js/migrations/from-ioredis.md +163 -0
- package/.agents/skills/upstash/upstash-redis-js/migrations/from-redis-node.md +205 -0
- package/.agents/skills/upstash/upstash-redis-js/overview.md +183 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/caching.md +58 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/distributed-locks.md +130 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/leaderboard.md +134 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/rate-limiting.md +187 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/session-management.md +217 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/batching-operations.md +76 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/data-serialization.md +134 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/error-handling.md +118 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/pipeline-optimization.md +105 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/redis-replicas.md +14 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/ttl-expiration.md +32 -0
- package/.agents/skills/upstash/upstash-redis-js/search/adapters.md +99 -0
- package/.agents/skills/upstash/upstash-redis-js/search/commands/aggregating.md +234 -0
- package/.agents/skills/upstash/upstash-redis-js/search/commands/aliases.md +76 -0
- package/.agents/skills/upstash/upstash-redis-js/search/commands/index-management.md +124 -0
- package/.agents/skills/upstash/upstash-redis-js/search/commands/querying.md +315 -0
- package/.agents/skills/upstash/upstash-redis-js/search/overview.md +155 -0
- package/.agents/skills/upstash/upstash-redis-start/overview.md +71 -0
- package/.agents/skills/upstash/upstash-search-js/overview.md +48 -0
- package/.agents/skills/upstash/upstash-search-js/quick-start.md +158 -0
- package/.agents/skills/upstash/upstash-search-js/sdk-overview.md +158 -0
- package/.agents/skills/upstash/upstash-vector-js/features/filtering-and-metadata.md +82 -0
- package/.agents/skills/upstash/upstash-vector-js/features/index-structure.md +193 -0
- package/.agents/skills/upstash/upstash-vector-js/features/namespaces.md +32 -0
- package/.agents/skills/upstash/upstash-vector-js/overview.md +44 -0
- package/.agents/skills/upstash/upstash-vector-js/sdk-methods.md +210 -0
- package/.agents/skills/upstash/upstash-workflow-js/agents.md +248 -0
- package/.agents/skills/upstash/upstash-workflow-js/basics/client.md +180 -0
- package/.agents/skills/upstash/upstash-workflow-js/basics/context.md +230 -0
- package/.agents/skills/upstash/upstash-workflow-js/basics/serve.md +70 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/flow-control.md +145 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/invoke.md +97 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/retries-failures-reliability.md +239 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/wait-for-event.md +97 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/webhooks.md +79 -0
- package/.agents/skills/upstash/upstash-workflow-js/how-to/local-dev.md +177 -0
- package/.agents/skills/upstash/upstash-workflow-js/how-to/middleware.md +166 -0
- package/.agents/skills/upstash/upstash-workflow-js/how-to/migrations.md +201 -0
- package/.agents/skills/upstash/upstash-workflow-js/how-to/realtime.md +186 -0
- package/.agents/skills/upstash/upstash-workflow-js/overview.md +55 -0
- package/.agents/skills/upstash/upstash-workflow-js/rest-api.md +156 -0
- package/.agents/skills/upstash/upstash-workflow-js/troubleshooting.md +201 -0
- package/.agents/skills/upstash-box-js/SKILL.md +248 -0
- package/.agents/skills/upstash-box-py/SKILL.md +280 -0
- package/.agents/skills/upstash-cli/SKILL.md +143 -0
- package/.agents/skills/upstash-qstash-js/SKILL.md +86 -0
- package/.agents/skills/upstash-qstash-js/advanced/callbacks.md +147 -0
- package/.agents/skills/upstash-qstash-js/advanced/deduplication.md +86 -0
- package/.agents/skills/upstash-qstash-js/advanced/dlq.md +164 -0
- package/.agents/skills/upstash-qstash-js/advanced/multi-region/summary.md +388 -0
- package/.agents/skills/upstash-qstash-js/advanced/multi-region/verify-multi-region-setup.ts +388 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/local-development.md +106 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/publishing-messages.md +144 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/queues-and-flow-control.md +148 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/schedules.md +177 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/url-groups.md +127 -0
- package/.agents/skills/upstash-qstash-js/verification/platform-specific/nextjs.md +171 -0
- package/.agents/skills/upstash-qstash-js/verification/receiver.md +213 -0
- package/.agents/skills/upstash-ratelimit-js/SKILL.md +31 -0
- package/.agents/skills/upstash-ratelimit-js/algorithms.md +84 -0
- package/.agents/skills/upstash-ratelimit-js/features.md +117 -0
- package/.agents/skills/upstash-ratelimit-js/methods-getting-started.md +77 -0
- package/.agents/skills/upstash-ratelimit-js/pricing-cost.md +146 -0
- package/.agents/skills/upstash-ratelimit-js/traffic-protection.md +77 -0
- package/.agents/skills/upstash-redis-js/SKILL.md +188 -0
- package/.agents/skills/upstash-redis-js/advanced-features/auto-pipeline.md +49 -0
- package/.agents/skills/upstash-redis-js/advanced-features/pipeline-and-transactions.md +42 -0
- package/.agents/skills/upstash-redis-js/advanced-features/scripting.md +124 -0
- package/.agents/skills/upstash-redis-js/data-structures/hashes.md +71 -0
- package/.agents/skills/upstash-redis-js/data-structures/json.md +133 -0
- package/.agents/skills/upstash-redis-js/data-structures/lists.md +72 -0
- package/.agents/skills/upstash-redis-js/data-structures/sets.md +90 -0
- package/.agents/skills/upstash-redis-js/data-structures/sorted-sets.md +126 -0
- package/.agents/skills/upstash-redis-js/data-structures/streams.md +196 -0
- package/.agents/skills/upstash-redis-js/data-structures/strings.md +73 -0
- package/.agents/skills/upstash-redis-js/migrations/from-ioredis.md +163 -0
- package/.agents/skills/upstash-redis-js/migrations/from-redis-node.md +205 -0
- package/.agents/skills/upstash-redis-js/patterns/caching.md +58 -0
- package/.agents/skills/upstash-redis-js/patterns/distributed-locks.md +130 -0
- package/.agents/skills/upstash-redis-js/patterns/leaderboard.md +134 -0
- package/.agents/skills/upstash-redis-js/patterns/rate-limiting.md +187 -0
- package/.agents/skills/upstash-redis-js/patterns/session-management.md +217 -0
- package/.agents/skills/upstash-redis-js/performance/batching-operations.md +76 -0
- package/.agents/skills/upstash-redis-js/performance/data-serialization.md +134 -0
- package/.agents/skills/upstash-redis-js/performance/error-handling.md +118 -0
- package/.agents/skills/upstash-redis-js/performance/pipeline-optimization.md +105 -0
- package/.agents/skills/upstash-redis-js/performance/redis-replicas.md +14 -0
- package/.agents/skills/upstash-redis-js/performance/ttl-expiration.md +32 -0
- package/.agents/skills/upstash-redis-js/search/adapters.md +99 -0
- package/.agents/skills/upstash-redis-js/search/commands/aggregating.md +234 -0
- package/.agents/skills/upstash-redis-js/search/commands/aliases.md +76 -0
- package/.agents/skills/upstash-redis-js/search/commands/index-management.md +124 -0
- package/.agents/skills/upstash-redis-js/search/commands/querying.md +315 -0
- package/.agents/skills/upstash-redis-js/search/overview.md +155 -0
- package/.agents/skills/upstash-redis-start/SKILL.md +76 -0
- package/.agents/skills/upstash-search-js/SKILL.md +53 -0
- package/.agents/skills/upstash-search-js/quick-start.md +158 -0
- package/.agents/skills/upstash-search-js/sdk-overview.md +158 -0
- package/.agents/skills/upstash-vector-js/SKILL.md +49 -0
- package/.agents/skills/upstash-vector-js/features/filtering-and-metadata.md +82 -0
- package/.agents/skills/upstash-vector-js/features/index-structure.md +193 -0
- package/.agents/skills/upstash-vector-js/features/namespaces.md +32 -0
- package/.agents/skills/upstash-vector-js/sdk-methods.md +210 -0
- package/.agents/skills/upstash-workflow-js/SKILL.md +60 -0
- package/.agents/skills/upstash-workflow-js/agents.md +248 -0
- package/.agents/skills/upstash-workflow-js/basics/client.md +180 -0
- package/.agents/skills/upstash-workflow-js/basics/context.md +230 -0
- package/.agents/skills/upstash-workflow-js/basics/serve.md +70 -0
- package/.agents/skills/upstash-workflow-js/features/flow-control.md +145 -0
- package/.agents/skills/upstash-workflow-js/features/invoke.md +97 -0
- package/.agents/skills/upstash-workflow-js/features/retries-failures-reliability.md +239 -0
- package/.agents/skills/upstash-workflow-js/features/wait-for-event.md +97 -0
- package/.agents/skills/upstash-workflow-js/features/webhooks.md +79 -0
- package/.agents/skills/upstash-workflow-js/how-to/local-dev.md +177 -0
- package/.agents/skills/upstash-workflow-js/how-to/middleware.md +166 -0
- package/.agents/skills/upstash-workflow-js/how-to/migrations.md +201 -0
- package/.agents/skills/upstash-workflow-js/how-to/realtime.md +186 -0
- package/.agents/skills/upstash-workflow-js/rest-api.md +156 -0
- package/.agents/skills/upstash-workflow-js/troubleshooting.md +201 -0
- package/dist/agents/coding.agent.d.ts +185 -42
- package/dist/agents/coding.agent.d.ts.map +1 -1
- package/dist/agents/coding.agent.js +42 -5
- package/dist/agents/coding.agent.js.map +1 -1
- package/dist/agents/manager.d.ts +216 -41
- package/dist/agents/manager.d.ts.map +1 -1
- package/dist/agents/manager.js +103 -140
- package/dist/agents/manager.js.map +1 -1
- package/dist/agents/security.agent.d.ts +3 -3
- package/dist/agents/swarm/development/lead.d.ts +3 -0
- package/dist/agents/swarm/development/lead.d.ts.map +1 -0
- package/dist/agents/swarm/development/lead.js +24 -0
- package/dist/agents/swarm/development/lead.js.map +1 -0
- package/dist/agents/swarm/main.d.ts +69 -0
- package/dist/agents/swarm/main.d.ts.map +1 -1
- package/dist/agents/swarm/main.js +65 -11
- package/dist/agents/swarm/main.js.map +1 -1
- package/dist/agents/swarm/registry.d.ts +2 -1
- package/dist/agents/swarm/registry.d.ts.map +1 -1
- package/dist/agents/swarm/registry.js +225 -95
- package/dist/agents/swarm/registry.js.map +1 -1
- package/dist/cli/composer.d.ts.map +1 -1
- package/dist/cli/composer.js +85 -30
- package/dist/cli/composer.js.map +1 -1
- package/dist/cli/confirm.d.ts +2 -2
- package/dist/cli/confirm.d.ts.map +1 -1
- package/dist/cli/confirm.js +373 -4
- package/dist/cli/confirm.js.map +1 -1
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +47 -2
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/format.d.ts +4 -0
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli/format.js +352 -65
- package/dist/cli/format.js.map +1 -1
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +80 -2
- package/dist/cli/interactive.js.map +1 -1
- package/dist/cli/menu.d.ts.map +1 -1
- package/dist/cli/menu.js +93 -83
- package/dist/cli/menu.js.map +1 -1
- package/dist/cli/render.d.ts.map +1 -1
- package/dist/cli/render.js +2 -1
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +262 -27
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/swarm.d.ts.map +1 -1
- package/dist/cli/swarm.js +13 -10
- package/dist/cli/swarm.js.map +1 -1
- package/dist/cli/theme.d.ts +7 -1
- package/dist/cli/theme.d.ts.map +1 -1
- package/dist/cli/theme.js +4 -16
- package/dist/cli/theme.js.map +1 -1
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +27 -4
- package/dist/cli/update.js.map +1 -1
- package/dist/config/env.d.ts +3 -1
- package/dist/config/env.d.ts.map +1 -1
- package/dist/config/env.js +22 -2
- package/dist/config/env.js.map +1 -1
- package/dist/config/models.d.ts +1 -0
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +17 -1
- package/dist/config/models.js.map +1 -1
- package/dist/documents/pdf.d.ts.map +1 -1
- package/dist/documents/pdf.js +282 -22
- package/dist/documents/pdf.js.map +1 -1
- package/dist/documents/slides.d.ts.map +1 -1
- package/dist/documents/slides.js +160 -30
- package/dist/documents/slides.js.map +1 -1
- package/dist/index.js +73 -18
- package/dist/index.js.map +1 -1
- package/dist/memory/history.js +1 -1
- package/dist/observability/doctor.d.ts.map +1 -1
- package/dist/observability/doctor.js +3 -0
- package/dist/observability/doctor.js.map +1 -1
- package/dist/runtime/progress.d.ts +5 -1
- package/dist/runtime/progress.d.ts.map +1 -1
- package/dist/runtime/progress.js.map +1 -1
- package/dist/runtime/swarm.d.ts +1 -1
- package/dist/runtime/swarm.d.ts.map +1 -1
- package/dist/runtime/swarm.js +19 -3
- package/dist/runtime/swarm.js.map +1 -1
- package/dist/runtime/tool-utils.d.ts +2 -0
- package/dist/runtime/tool-utils.d.ts.map +1 -1
- package/dist/runtime/tool-utils.js +91 -0
- package/dist/runtime/tool-utils.js.map +1 -1
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +16 -0
- package/dist/skills/loader.js.map +1 -1
- package/dist/test-call.d.ts +2 -0
- package/dist/test-call.d.ts.map +1 -0
- package/dist/test-call.js +29 -0
- package/dist/test-call.js.map +1 -0
- package/dist/test-manager-call.d.ts +2 -0
- package/dist/test-manager-call.d.ts.map +1 -0
- package/dist/test-manager-call.js +138 -0
- package/dist/test-manager-call.js.map +1 -0
- package/dist/test-manager-filtered.d.ts +2 -0
- package/dist/test-manager-filtered.d.ts.map +1 -0
- package/dist/test-manager-filtered.js +130 -0
- package/dist/test-manager-filtered.js.map +1 -0
- package/dist/test-mcp-call.d.ts +2 -0
- package/dist/test-mcp-call.d.ts.map +1 -0
- package/dist/test-mcp-call.js +103 -0
- package/dist/test-mcp-call.js.map +1 -0
- package/dist/tools/composio.tool.d.ts +1 -1
- package/dist/tools/composio.tool.d.ts.map +1 -1
- package/dist/tools/composio.tool.js +7 -16
- package/dist/tools/composio.tool.js.map +1 -1
- package/dist/tools/daytona-browser.tool.js +1 -1
- package/dist/tools/daytona-browser.tool.js.map +1 -1
- package/dist/tools/executive.tool.d.ts +40 -0
- package/dist/tools/executive.tool.d.ts.map +1 -0
- package/dist/tools/executive.tool.js +74 -0
- package/dist/tools/executive.tool.js.map +1 -0
- package/dist/tools/filesystem.tool.d.ts +183 -40
- package/dist/tools/filesystem.tool.d.ts.map +1 -1
- package/dist/tools/filesystem.tool.js +564 -111
- package/dist/tools/filesystem.tool.js.map +1 -1
- package/dist/tools/mcp.tool.d.ts +56 -0
- package/dist/tools/mcp.tool.d.ts.map +1 -0
- package/dist/tools/mcp.tool.js +285 -0
- package/dist/tools/mcp.tool.js.map +1 -0
- package/dist/tools/osint.tool.d.ts +4 -4
- package/dist/tools/pentest.tool.d.ts +2 -2
- package/dist/tools/setup-assistant.tool.d.ts +1 -1
- package/dist/tools/setup-assistant.tool.js +1 -1
- package/dist/tools/setup-assistant.tool.js.map +1 -1
- package/dist/workspace/paths.d.ts +1 -0
- package/dist/workspace/paths.d.ts.map +1 -1
- package/dist/workspace/paths.js +3 -4
- package/dist/workspace/paths.js.map +1 -1
- package/package.json +8 -4
- package/scripts/postinstall.mjs +19 -4
- package/scripts/release-github.mjs +11 -11
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# Workflow Reliability Features
|
|
2
|
+
|
|
3
|
+
This documentation provides a consolidated reference for reliability mechanisms in Upstash Workflow, focusing on retries, failure handling, and the Dead Letter Queue (DLQ). It is optimized for AI‑driven execution but remains clear for developers.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Core Reliability Concepts
|
|
8
|
+
|
|
9
|
+
Upstash Workflow ensures that workflow runs are durable, recoverable, and traceable. Reliability is achieved through:
|
|
10
|
+
|
|
11
|
+
- Automatic retries for transient failures
|
|
12
|
+
- Failure handling via `failureFunction` or `failureUrl`
|
|
13
|
+
- DLQ for storing permanently failed runs
|
|
14
|
+
- Manual recovery actions: restart, resume, rerun failure function
|
|
15
|
+
- Mechanisms to prevent retries when failure is intentional
|
|
16
|
+
|
|
17
|
+
These mechanisms work together to guarantee that no failed execution is lost and that failures can be observed and handled.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Automatic Retries
|
|
22
|
+
|
|
23
|
+
Workflow steps automatically retry when they fail, using configurable retry count and delay.
|
|
24
|
+
|
|
25
|
+
### Retry Parameters
|
|
26
|
+
|
|
27
|
+
- `retries`: How many times the step will retry
|
|
28
|
+
- `retryDelay`: A math expression (string) returning delay in milliseconds; can use `retried` variable
|
|
29
|
+
|
|
30
|
+
### Common Pitfalls
|
|
31
|
+
|
|
32
|
+
- The delay expression must be a _string_; raw numbers disable dynamic calculation.
|
|
33
|
+
- A workflow only moves to DLQ after **all** retries fail.
|
|
34
|
+
|
|
35
|
+
### Example: Configure Retry Count + Delay
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { Client, WorkflowNonRetryableError, serve } from "@upstash/workflow";
|
|
39
|
+
|
|
40
|
+
// Trigger with custom retry settings
|
|
41
|
+
const client = new Client({ token: process.env.WORKFLOW_TOKEN! });
|
|
42
|
+
await client.trigger({
|
|
43
|
+
url: "https://example.com/workflow",
|
|
44
|
+
retries: 5,
|
|
45
|
+
retryDelay: "(1 + retried) * 2000", // 2s, 4s, 6s...
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Workflow with steps that may intentionally skip retries
|
|
49
|
+
export const { POST } = serve(async (context) => {
|
|
50
|
+
const shouldFail = await context.run("check", () => true);
|
|
51
|
+
|
|
52
|
+
if (shouldFail) {
|
|
53
|
+
// Skips retry cycle and sends directly to failure handling
|
|
54
|
+
throw new WorkflowNonRetryableError("Bad state");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
await context.run("process", () => doWork());
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Preventing Retries
|
|
64
|
+
|
|
65
|
+
### When to Stop Retries
|
|
66
|
+
|
|
67
|
+
Use these when failure is expected or should halt execution immediately:
|
|
68
|
+
|
|
69
|
+
- `WorkflowNonRetryableError` → Fail fast, trigger failure function, enter DLQ
|
|
70
|
+
- `context.cancel()` → Stop workflow intentionally, no DLQ, no failure function
|
|
71
|
+
- Conditional returns → Graceful early exit without error
|
|
72
|
+
|
|
73
|
+
### Pitfalls
|
|
74
|
+
|
|
75
|
+
- `context.cancel()` marks the run as **canceled**, not failed — no failure handling executes.
|
|
76
|
+
- Throwing any error _other than_ `WorkflowNonRetryableError` will still trigger retries.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Failure Handling
|
|
81
|
+
|
|
82
|
+
You can handle workflow failures using either:
|
|
83
|
+
|
|
84
|
+
- `failureFunction` (runs in your workflow environment)
|
|
85
|
+
- `failureUrl` (external callback endpoint)
|
|
86
|
+
|
|
87
|
+
Only **one** can be configured — they are mutually exclusive.
|
|
88
|
+
|
|
89
|
+
### Failure Function Behavior
|
|
90
|
+
|
|
91
|
+
- Runs after all retries fail
|
|
92
|
+
- Receives failure metadata and workflow context
|
|
93
|
+
- Cannot create new workflow steps; `context` is read‑only
|
|
94
|
+
- Is retried if it fails
|
|
95
|
+
- Can be manually retried from the DLQ
|
|
96
|
+
|
|
97
|
+
### Failure Function Parameters
|
|
98
|
+
|
|
99
|
+
- `context.workflowRunId`
|
|
100
|
+
- `context.url`
|
|
101
|
+
- `context.requestPayload`
|
|
102
|
+
- `context.headers`
|
|
103
|
+
- `context.env`
|
|
104
|
+
- `failStatus`
|
|
105
|
+
- `failResponse`
|
|
106
|
+
- `failHeaders`
|
|
107
|
+
|
|
108
|
+
### Example: Workflow + Failure Function + Prevent‑Retry Logic
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
export const { POST } = serve(
|
|
112
|
+
async (context) => {
|
|
113
|
+
const ok = await context.run("verify", () => verifySomething());
|
|
114
|
+
|
|
115
|
+
if (!ok) {
|
|
116
|
+
throw new WorkflowNonRetryableError("Verification failed");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const shouldAbort = await context.run("check", () => false);
|
|
120
|
+
if (shouldAbort) {
|
|
121
|
+
await context.cancel();
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
await context.run("execute", () => doWork());
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
failureFunction: async ({ context, failStatus, failResponse }) => {
|
|
129
|
+
// Logging / cleanup / alerts
|
|
130
|
+
await logFailure(context.workflowRunId, failStatus, failResponse);
|
|
131
|
+
},
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Dead Letter Queue (DLQ)
|
|
139
|
+
|
|
140
|
+
A workflow enters the DLQ when:
|
|
141
|
+
|
|
142
|
+
- A step fails _after all retries_
|
|
143
|
+
- A `WorkflowNonRetryableError` is thrown
|
|
144
|
+
- `failureFunction` also fails (visible as failed in DLQ)
|
|
145
|
+
|
|
146
|
+
### Retention
|
|
147
|
+
|
|
148
|
+
- Free: 3 days
|
|
149
|
+
- Pay‑as‑you‑go: 1 week
|
|
150
|
+
- Fixed: Up to 3 months
|
|
151
|
+
|
|
152
|
+
After retention expires, items cannot be recovered.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## DLQ Recovery Actions
|
|
157
|
+
|
|
158
|
+
You may perform these actions from the dashboard or programmatically.
|
|
159
|
+
|
|
160
|
+
### 1. Resume
|
|
161
|
+
|
|
162
|
+
Continue from the failed step while keeping previous step results.
|
|
163
|
+
|
|
164
|
+
### 2. Restart
|
|
165
|
+
|
|
166
|
+
Start the entire workflow from scratch, discarding previous results.
|
|
167
|
+
|
|
168
|
+
### 3. Rerun Failure Function
|
|
169
|
+
|
|
170
|
+
Retry the failure handler **only if it previously failed**.
|
|
171
|
+
|
|
172
|
+
### Example: All DLQ Actions
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
import { Client } from "@upstash/workflow";
|
|
176
|
+
const client = new Client({ token: process.env.WORKFLOW_TOKEN! });
|
|
177
|
+
|
|
178
|
+
await client.dlq.resume({ dlqId: "dlq-1", retries: 3 }); // Continue run
|
|
179
|
+
await client.dlq.restart({ dlqId: "dlq-2", retries: 3 }); // Restart
|
|
180
|
+
await client.dlq.retryFailureFunction({ dlqId: "dlq-3" }); // Retry failure handler
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Pitfalls
|
|
184
|
+
|
|
185
|
+
- `retryFailureFunction` is only allowed when the failure function failed.
|
|
186
|
+
- `resume` cannot be used if workflow code changed before the failure point.
|
|
187
|
+
- `restart` re-executes everything, including expensive steps.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Failure URL (Advanced Option)
|
|
192
|
+
|
|
193
|
+
Use when failure must be handled by a separate service.
|
|
194
|
+
|
|
195
|
+
### Notes
|
|
196
|
+
|
|
197
|
+
- Use **either** `failureFunction` **or** `failureUrl`.
|
|
198
|
+
- Recommended only when your primary app might be offline.
|
|
199
|
+
- Failure URL receives a structured JSON payload about the failed request.
|
|
200
|
+
|
|
201
|
+
### Example
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
export const { POST } = serve(
|
|
205
|
+
async (context) => {
|
|
206
|
+
await context.run("work", () => doWork());
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
failureUrl: "https://example.com/failure-handler",
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Debugging Failed Runs
|
|
217
|
+
|
|
218
|
+
DLQ entries store:
|
|
219
|
+
|
|
220
|
+
- Request + response headers
|
|
221
|
+
- Payloads
|
|
222
|
+
- Failure metadata
|
|
223
|
+
- Failure function state
|
|
224
|
+
|
|
225
|
+
Use the dashboard filters (workflow run ID, URL, failure function state) to identify and debug root causes.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Summary
|
|
230
|
+
|
|
231
|
+
This skill unifies all Workflow reliability controls:
|
|
232
|
+
|
|
233
|
+
- Retries (automatic, configurable)
|
|
234
|
+
- Failure handling (`failureFunction`, `failureUrl`)
|
|
235
|
+
- DLQ retention + recovery
|
|
236
|
+
- Fast‑fail mechanisms (`WorkflowNonRetryableError`, `cancel`, conditional exits)
|
|
237
|
+
- Manual recovery operations (resume, restart, retry failure function)
|
|
238
|
+
|
|
239
|
+
Together these features ensure workflows are resilient, debuggable, and recoverable under all failure scenarios.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Wait for Event
|
|
2
|
+
|
|
3
|
+
Use this feature to pause workflow execution until an external event arrives. It allows building asynchronous, event‑driven workflows without holding compute resources.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
`context.waitForEvent()` suspends the workflow and registers a waiter under an event ID. When a matching `notify` call is sent, the workflow resumes with the provided event data.
|
|
10
|
+
|
|
11
|
+
• Each waiter has a timeout. If the event does not arrive in time, the workflow continues with `{ timeout: true }`.
|
|
12
|
+
• Maximum timeout depends on your pricing tier.
|
|
13
|
+
• Multiple workflow runs may wait on the same event ID; a notify call resumes all of them.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Key Concepts & Pitfalls
|
|
18
|
+
|
|
19
|
+
### Event IDs
|
|
20
|
+
|
|
21
|
+
Use unique event IDs to avoid heavy fan‑out notifications.
|
|
22
|
+
|
|
23
|
+
Example patterns:
|
|
24
|
+
• `order-123-processing-complete`
|
|
25
|
+
• `user-42-email-verified`
|
|
26
|
+
|
|
27
|
+
### Race Conditions
|
|
28
|
+
|
|
29
|
+
A notify call sent _before_ the workflow begins waiting is lost.
|
|
30
|
+
|
|
31
|
+
To avoid this:
|
|
32
|
+
• Always inspect the notify response.
|
|
33
|
+
• Retry if no waiters were found.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Combined Example
|
|
38
|
+
|
|
39
|
+
Below is a single TypeScript example showing waiting for an event, handling timeouts, and safely notifying:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { serve } from "@upstash/workflow/nextjs";
|
|
43
|
+
import { Client } from "@upstash/workflow";
|
|
44
|
+
|
|
45
|
+
// Workflow that waits for an event
|
|
46
|
+
export const { POST } = serve(async (context) => {
|
|
47
|
+
const { orderId } = context.requestPayload;
|
|
48
|
+
const eventId = `order-${orderId}-processed`;
|
|
49
|
+
|
|
50
|
+
// Wait for the event with timeout
|
|
51
|
+
const { eventData, timeout } = await context.waitForEvent(
|
|
52
|
+
"wait-for-order-processing", // step name
|
|
53
|
+
eventId, // event id
|
|
54
|
+
{
|
|
55
|
+
timeout: "1d", // optional timeout
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
if (timeout) {
|
|
60
|
+
// handle timeout here
|
|
61
|
+
await context.run("timeout-handler", async () => {
|
|
62
|
+
console.log("Order processing timed out");
|
|
63
|
+
});
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Continue workflow using eventData
|
|
68
|
+
await context.run("process-completed-order", async () => {
|
|
69
|
+
console.log("Order processed:", eventData);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// External notifier (safe retry pattern)
|
|
74
|
+
const client = new Client({ token: "<WORKFLOW_TOKEN>" });
|
|
75
|
+
|
|
76
|
+
async function notifyProcessingComplete(orderId: string, payload: any) {
|
|
77
|
+
const eventId = `order-${orderId}-processed`;
|
|
78
|
+
|
|
79
|
+
// First attempt - returns array of NotifyResponse
|
|
80
|
+
const waiters = await client.notify({ eventId, eventData: payload });
|
|
81
|
+
|
|
82
|
+
if (waiters > 0) return waiters;
|
|
83
|
+
|
|
84
|
+
// Retry if no workflows were waiting
|
|
85
|
+
await new Promise((r) => setTimeout(r, 3000));
|
|
86
|
+
return await client.notify({ eventId, eventData: payload });
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Best Practices
|
|
93
|
+
|
|
94
|
+
• Generate event IDs that uniquely identify a specific workflow instance.
|
|
95
|
+
• Always handle the timeout case explicitly.
|
|
96
|
+
• On notification, check the returned array length to detect if any workflows were waiting.
|
|
97
|
+
• Prefer one event ID per workflow run to avoid notifying large groups.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
## Webhooks
|
|
2
|
+
|
|
3
|
+
This skill teaches agents how to use webhooks inside Upstash Workflow to pause execution, wait for external callbacks, and resume reliably. It covers creation, waiting, validation, and multi-step usage.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
### Key Concepts
|
|
8
|
+
|
|
9
|
+
• **Webhook URLs are unique per context.createWebhook() call**.
|
|
10
|
+
• **Workflow execution pauses** when calling `context.waitForWebhook()` until the webhook receives a request or times out.
|
|
11
|
+
• **Lookback protection** ensures the workflow still receives early webhook calls.
|
|
12
|
+
• **Workflows remain dormant** during the waiting period, avoiding compute cost.
|
|
13
|
+
• **Webhooks are ideal for third‑party APIs** that support callback URLs.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
### Core Workflow: Create → Call External API → Wait → Resume
|
|
18
|
+
|
|
19
|
+
Below is a consolidated example showing:
|
|
20
|
+
• Creating a webhook
|
|
21
|
+
• Passing it to an external API
|
|
22
|
+
• Handling the callback
|
|
23
|
+
• Waiting for multiple updates
|
|
24
|
+
• Error/timeout handling
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { serve } from "@upstash/workflow/nextjs";
|
|
28
|
+
|
|
29
|
+
export const { POST } = serve(async (context) => {
|
|
30
|
+
// Create a unique webhook for this workflow
|
|
31
|
+
const webhook = await context.createWebhook("create webhook");
|
|
32
|
+
|
|
33
|
+
// Trigger an external service, sending it the callback URL
|
|
34
|
+
await context.call("trigger-external", {
|
|
35
|
+
url: "https://api.example.com/process",
|
|
36
|
+
method: "POST",
|
|
37
|
+
body: { webhookUrl: webhook.webhookUrl },
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Loop: wait for progress updates until service signals completion
|
|
41
|
+
let updates = [];
|
|
42
|
+
while (true) {
|
|
43
|
+
const res = await context.waitForWebhook(`wait update`, webhook, "5m");
|
|
44
|
+
|
|
45
|
+
if (res.timeout) break; // no progress received
|
|
46
|
+
|
|
47
|
+
const req = res.request;
|
|
48
|
+
const payload = await req.json();
|
|
49
|
+
updates.push(payload);
|
|
50
|
+
|
|
51
|
+
if (req.headers.get("x-task-finished") === "true") break;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return updates;
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
### Webhook Reliability: Lookback Protection
|
|
61
|
+
|
|
62
|
+
**Common pitfall:** external systems may call the webhook _before_ the workflow reaches `waitForWebhook()`.
|
|
63
|
+
|
|
64
|
+
Upstash automatically stores early webhook calls. The next `waitForWebhook()` will immediately resolve with the stored request.
|
|
65
|
+
|
|
66
|
+
This avoids race conditions and eliminates the need for manual buffering.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### When to Use Webhooks vs. Wait for Event
|
|
71
|
+
|
|
72
|
+
Use **webhooks** when:
|
|
73
|
+
• integrating with third‑party APIs
|
|
74
|
+
• the external system invokes a callback URL
|
|
75
|
+
• you need race‑condition‑safe behavior
|
|
76
|
+
|
|
77
|
+
Use **Wait for Event** when:
|
|
78
|
+
• you control the notifying system and can use the Workflow Client
|
|
79
|
+
• you don't need lookback semantics
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# Local Development for Upstash Workflow
|
|
2
|
+
|
|
3
|
+
This documentation explains how to run Upstash Workflow locally using the QStash development server and how to expose your local app using a public tunnel such as ngrok. It focuses on practical usage and TypeScript integration.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Upstash Workflow uses Upstash QStash under the hood. During development you can:
|
|
8
|
+
|
|
9
|
+
- Use the **automatic dev server** by setting `QSTASH_DEV=true`. The SDK downloads the QStash CLI binary, spawns the server, and verifies signatures with its dev keys. No tokens or signing keys required.
|
|
10
|
+
- Run a **local QStash development server** manually via the CLI and wire credentials yourself.
|
|
11
|
+
- Optionally expose your local server using **ngrok** if you want to test with the production QStash.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Automatic dev server (recommended)
|
|
16
|
+
|
|
17
|
+
Set `QSTASH_DEV=true` in your environment and that's it. Workflow's `serve()` endpoint and the `Client` both auto-detect it:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
QSTASH_DEV=true
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
// app/api/workflow/route.ts
|
|
25
|
+
import { serve } from "@upstash/workflow/nextjs";
|
|
26
|
+
|
|
27
|
+
export const { POST } = serve(async (context) => {
|
|
28
|
+
await context.run("step-1", () => console.log("running locally"));
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { Client } from "@upstash/workflow";
|
|
34
|
+
|
|
35
|
+
const client = new Client({ token: process.env.QSTASH_TOKEN ?? "" });
|
|
36
|
+
|
|
37
|
+
await client.trigger({
|
|
38
|
+
url: "http://localhost:3000/api/workflow",
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
When `QSTASH_DEV=true`:
|
|
43
|
+
|
|
44
|
+
- The underlying `@upstash/qstash` client downloads the QStash CLI binary on first use, spawns the dev server on port `8080` (override via `QSTASH_DEV_PORT`), and reuses an already-running server on that port instead of spawning a duplicate.
|
|
45
|
+
- `serve()` builds a dev-mode `Receiver` internally, so signature verification works against the dev server's deterministic signing keys with no real credentials.
|
|
46
|
+
- It's a no-op in production (`NODE_ENV=production`), during `next build`, and in browser/edge runtimes.
|
|
47
|
+
|
|
48
|
+
**Next.js edge routes:** the edge runtime cannot spawn child processes. If your workflow route runs on the Edge Runtime, call `registerQStashDev()` from `instrumentation.ts` so the binary starts at Next.js boot:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
// instrumentation.ts
|
|
52
|
+
import { registerQStashDev } from "@upstash/qstash/nextjs";
|
|
53
|
+
|
|
54
|
+
export function register() {
|
|
55
|
+
registerQStashDev();
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
See the [QStash Local Development skill](../../upstash-qstash-js/fundamentals/local-development.md) for the full reference, including pitfalls and CLI options.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 1. Start the QStash Local Development Server
|
|
64
|
+
|
|
65
|
+
If you'd rather manage the dev server yourself instead of using the automatic flow above, run the CLI manually.
|
|
66
|
+
|
|
67
|
+
Use the QStash CLI:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
npx @upstash/qstash-cli dev
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The CLI prints:
|
|
74
|
+
|
|
75
|
+
- QSTASH_TOKEN
|
|
76
|
+
- QSTASH_CURRENT_SIGNING_KEY
|
|
77
|
+
- QSTASH_NEXT_SIGNING_KEY
|
|
78
|
+
- Local server URL (default: `http://127.0.0.1:8080`)
|
|
79
|
+
|
|
80
|
+
Set these values in your `.env` file so your workflow client uses the local environment.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 2. Set Local Environment Variables
|
|
85
|
+
|
|
86
|
+
Use the environment values printed by the CLI:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
QSTASH_URL="http://127.0.0.1:8080"
|
|
90
|
+
QSTASH_TOKEN="<token-from-cli>"
|
|
91
|
+
QSTASH_CURRENT_SIGNING_KEY="<cur-key>"
|
|
92
|
+
QSTASH_NEXT_SIGNING_KEY="<next-key>"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
These ensure all workflow requests are routed locally.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 3. Trigger Workflows Using Local URLs
|
|
100
|
+
|
|
101
|
+
A common pattern is determining the base URL dynamically based on environment variables. Below is an example that demonstrates:
|
|
102
|
+
|
|
103
|
+
- Local development (localhost)
|
|
104
|
+
- Production deployments (auto-detected env)
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { Client } from "@upstash/workflow";
|
|
108
|
+
|
|
109
|
+
const client = Client();
|
|
110
|
+
|
|
111
|
+
// In production, Vercel sets VERCEL_URL. Otherwise use localhost.
|
|
112
|
+
const BASE_URL = process.env.VERCEL_URL
|
|
113
|
+
? `https://${process.env.VERCEL_URL}`
|
|
114
|
+
: `http://localhost:3000`;
|
|
115
|
+
|
|
116
|
+
// Trigger a workflow with retries
|
|
117
|
+
const { workflowRunId } = await client.trigger({
|
|
118
|
+
url: `${BASE_URL}/api/workflow`, // Local or production
|
|
119
|
+
retries: 3, // Optional retry logic
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
console.log("Workflow run:", workflowRunId);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Common mistakes:**
|
|
126
|
+
|
|
127
|
+
- Forgetting to include the full URL including `http://` or `https://`.
|
|
128
|
+
- Using a production URL while the local QStash server is running.
|
|
129
|
+
- Missing environment variables.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 4. Using ngrok (Optional)
|
|
134
|
+
|
|
135
|
+
If your workflow must be reachable from the managed Upstash servers (not local), expose your local server publicly.
|
|
136
|
+
|
|
137
|
+
### Install & authenticate
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
ngrok config add-authtoken <YOUR-AUTH-TOKEN>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Start a tunnel
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
ngrok http 3000
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
ngrok outputs a public URL:
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
Forwarding https://1234abcd.ngrok.io -> http://localhost:3000
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Use this public URL instead of localhost:
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
const BASE_URL = "https://1234abcd.ngrok.io"; // Public tunnel
|
|
159
|
+
|
|
160
|
+
await client.trigger({
|
|
161
|
+
url: `${BASE_URL}/api/workflow`,
|
|
162
|
+
retries: 3,
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Pitfall:** Your ngrok port must match your dev server port, otherwise all workflow calls will fail.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Summary
|
|
171
|
+
|
|
172
|
+
- Start QStash locally using `qstash-cli dev`.
|
|
173
|
+
- Copy generated environment variables into `.env`.
|
|
174
|
+
- Use local URLs in TypeScript clients while developing.
|
|
175
|
+
- Optionally expose your server with ngrok if you need remote access.
|
|
176
|
+
|
|
177
|
+
This setup ensures fast workflow iteration without deploying your app.
|