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,180 @@
|
|
|
1
|
+
# Workflow Client Basics
|
|
2
|
+
|
|
3
|
+
This skill provides guidance for using the Workflow Client to trigger, cancel, inspect, resume, and manage workflow runs. It focuses on TypeScript usage patterns, argument structures, and common pitfalls.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Core Operations
|
|
8
|
+
|
|
9
|
+
### Triggering Workflow Runs (`client.trigger`)
|
|
10
|
+
|
|
11
|
+
Starts one or multiple workflow runs with optional payload, metadata, retry logic, and flow control.
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// Single and multiple triggers
|
|
15
|
+
const single = await client.trigger({
|
|
16
|
+
url: "https://your-endpoint/workflow", // required
|
|
17
|
+
body: { msg: "hello" }, // optional payload
|
|
18
|
+
headers: { "x-user": "123" }, // optional headers
|
|
19
|
+
workflowRunId: "custom-id", // custom unique identifier
|
|
20
|
+
retries: 3, // retry count for steps
|
|
21
|
+
retryDelay: "1000 * (1 + retried)", // expression-based retry delay
|
|
22
|
+
delay: "10s", // start later
|
|
23
|
+
notBefore: Math.floor(Date.now() / 1000) + 60, // absolute schedule
|
|
24
|
+
label: "my-run", // dashboard filtering
|
|
25
|
+
disableTelemetry: true, // opt‑out telemetry
|
|
26
|
+
flowControl: {
|
|
27
|
+
// concurrency & rate limiting
|
|
28
|
+
key: "user-key",
|
|
29
|
+
rate: 10,
|
|
30
|
+
parallelism: 5,
|
|
31
|
+
period: "10m",
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const multiple = await client.trigger([
|
|
36
|
+
{ url: "https://api/runA", body: { a: 1 } },
|
|
37
|
+
{ url: "https://api/runB", retries: 5 },
|
|
38
|
+
]);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Pitfalls**:
|
|
42
|
+
|
|
43
|
+
- `workflowRunId` must be unique; collisions cause errors.
|
|
44
|
+
- `delay` is ignored if `notBefore` is provided.
|
|
45
|
+
- Using `url` incorrectly (missing protocol or dynamic segments) leads to invalid workflow endpoints.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
### Canceling Workflow Runs (`client.cancel`)
|
|
50
|
+
|
|
51
|
+
Cancel runs by ID, by URL prefix, or all active/pending runs.
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
await client.cancel({ ids: ["wfr_123", "wfr_456"] });
|
|
55
|
+
await client.cancel({ urlStartingWith: "https://your-endpoint.com" });
|
|
56
|
+
await client.cancel({ all: true });
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- `ids` accepts both string and array, but mixing with other filters is not supported.
|
|
60
|
+
- `urlStartingWith` cancels _all_ descendant paths—use carefully.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### Retrieving Logs (`client.logs`)
|
|
65
|
+
|
|
66
|
+
Fetch workflow execution logs with filtering and cursor-based pagination.
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
const { runs, cursor } = await client.logs({
|
|
70
|
+
workflowRunId: "wfr_123", // filter a specific run
|
|
71
|
+
workflowUrl: "https://endpoint", // fetch logs for an endpoint
|
|
72
|
+
state: "RUN_FAILED", // filter by execution state
|
|
73
|
+
count: 50, // limit return size
|
|
74
|
+
workflowCreatedAt: 1700000000, // Unix timestamp
|
|
75
|
+
cursor: undefined, // pagination
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### Notifying Events (`client.notify`)
|
|
82
|
+
|
|
83
|
+
Notify workflows paused at `context.waitForEvent`.
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
await client.notify({
|
|
87
|
+
eventId: "order-paid",
|
|
88
|
+
eventData: { orderId: 1 }, // delivered to waiting workflow
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**Pitfall**: If no workflow is waiting, no error is thrown.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### Fetching Waiting Workflows (`client.getWaiters`)
|
|
97
|
+
|
|
98
|
+
Retrieve active waiters waiting for a specific event.
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
const waiters = await client.getWaiters({ eventId: "order-paid" });
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
This is useful for debugging or coordinating external signals.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Dead Letter Queue (DLQ) Operations
|
|
109
|
+
|
|
110
|
+
### Listing DLQ Messages (`client.dlq.list`)
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
const { messages, cursor } = await client.dlq.list({
|
|
114
|
+
cursor,
|
|
115
|
+
count: 20,
|
|
116
|
+
filter: {
|
|
117
|
+
fromDate: Date.now() - 86400000,
|
|
118
|
+
toDate: Date.now(),
|
|
119
|
+
url: "https://your-endpoint.com",
|
|
120
|
+
responseStatus: 500,
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- Date fields use Unix **ms**, not seconds.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### Retry Failure Callback (`client.dlq.retryFailureFunction`)
|
|
130
|
+
|
|
131
|
+
If a workflow's `failureFunction`/`failureUrl` call failed:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
await client.dlq.retryFailureFunction({ dlqId: "dlq-123" });
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### Restarting DLQ Runs (`client.dlq.restart`)
|
|
140
|
+
|
|
141
|
+
Restart from the **beginning** of the workflow.
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
await client.dlq.restart({
|
|
145
|
+
dlqId: ["dlq-1", "dlq-2"],
|
|
146
|
+
retries: 5,
|
|
147
|
+
flowControl: {
|
|
148
|
+
key: "restart-group",
|
|
149
|
+
parallelism: 10,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### Resuming DLQ Runs (`client.dlq.resume`)
|
|
157
|
+
|
|
158
|
+
Continue from the **failed step**.
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
await client.dlq.resume({
|
|
162
|
+
dlqId: "dlq-123",
|
|
163
|
+
retries: 3,
|
|
164
|
+
flowControl: {
|
|
165
|
+
key: "resume-group",
|
|
166
|
+
rate: 5,
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Common confusion**:
|
|
172
|
+
|
|
173
|
+
- `restart` = new run from step 0.
|
|
174
|
+
- `resume` = same run continues at the failed step.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## General Tips for TS Consumers
|
|
179
|
+
|
|
180
|
+
- Use flow control when bulk‑triggering or restarting large batches to avoid rate limits.
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Workflow Context Basics
|
|
2
|
+
|
|
3
|
+
This skill documents all workflow context functions available inside a TypeScript workflow. It focuses on how these APIs behave, how their parameters interact, and common pitfalls when composing them into reliable long‑running workflows.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## context.api
|
|
8
|
+
|
|
9
|
+
`context.api` provides typed integrations for OpenAI, Anthropic, and Resend. These calls behave like `context.call` but enforce the correct operation names and body types.
|
|
10
|
+
|
|
11
|
+
### Key points
|
|
12
|
+
|
|
13
|
+
- Each provider exposes a `.call(stepName, config)` function.
|
|
14
|
+
- `token` is always required.
|
|
15
|
+
- The `operation` field selects the API method.
|
|
16
|
+
- `body` must match the provider's type definitions.
|
|
17
|
+
- Returns `{ status, body }`.
|
|
18
|
+
|
|
19
|
+
### Example (combined)
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// OpenAI + Anthropic + Resend usage
|
|
23
|
+
const openai = await context.api.openai.call("openai chat", {
|
|
24
|
+
token: process.env.OPENAI_API_KEY!,
|
|
25
|
+
operation: "chat.completions.create",
|
|
26
|
+
body: {
|
|
27
|
+
model: "gpt-4o",
|
|
28
|
+
messages: [
|
|
29
|
+
{ role: "system", content: "Hello" },
|
|
30
|
+
{ role: "user", content: "Hi" },
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const anthropic = await context.api.anthropic.call("anthropic message", {
|
|
36
|
+
token: process.env.ANTHROPIC_API_KEY!,
|
|
37
|
+
operation: "messages.create",
|
|
38
|
+
body: {
|
|
39
|
+
model: "claude-3-5-sonnet-20241022",
|
|
40
|
+
max_tokens: 1024,
|
|
41
|
+
messages: [{ role: "user", content: "Hello" }],
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Resend email
|
|
46
|
+
const email = await context.api.resend.call("send email", {
|
|
47
|
+
token: process.env.RESEND_API_KEY!,
|
|
48
|
+
headers: { "content-type": "application/json" },
|
|
49
|
+
body: {
|
|
50
|
+
from: "Acme <onboarding@resend.dev>",
|
|
51
|
+
to: ["someone@example.com"],
|
|
52
|
+
subject: "Welcome",
|
|
53
|
+
html: "<p>Hi!</p>",
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## context.call
|
|
61
|
+
|
|
62
|
+
Performs an HTTP request with long execution windows (up to 12 hours). Always returns a response, even for non‑2xx status codes.
|
|
63
|
+
|
|
64
|
+
### Important parameters
|
|
65
|
+
|
|
66
|
+
- `url`: required.
|
|
67
|
+
- `method`: defaults to `GET`.
|
|
68
|
+
- `headers`: object.
|
|
69
|
+
- `body`: body as string.
|
|
70
|
+
- `retries`: number of retry attempts.
|
|
71
|
+
- `retryDelay`: retry delay expression as string or number (in milliseconds).
|
|
72
|
+
- `flowControl`: throttling config.
|
|
73
|
+
- `timeout`: seconds for each attempt.
|
|
74
|
+
- `workflow`: used only when invoking a workflow inside `serveMany`.
|
|
75
|
+
|
|
76
|
+
### Example (showing most fields)
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
const response = await context.call("sync user", {
|
|
80
|
+
url: "https://api.example.com/user",
|
|
81
|
+
method: "POST",
|
|
82
|
+
headers: { authorization: `Bearer ${process.env.TOKEN}` },
|
|
83
|
+
body: JSON.stringify({ id: userId, name }),
|
|
84
|
+
retries: 3,
|
|
85
|
+
retryDelay: "pow(2, retried)", // exponential
|
|
86
|
+
timeout: 20,
|
|
87
|
+
flowControl: {
|
|
88
|
+
key: "user-sync",
|
|
89
|
+
rate: 5,
|
|
90
|
+
parallelism: 2,
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Pitfalls
|
|
96
|
+
|
|
97
|
+
- Localhost requests fail unless tunneled.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## context.cancel
|
|
102
|
+
|
|
103
|
+
Cancels the current workflow run.
|
|
104
|
+
|
|
105
|
+
- Workflow is marked **canceled**, not failed.
|
|
106
|
+
- `failureFunction` does not run.
|
|
107
|
+
- No DLQ entry.
|
|
108
|
+
|
|
109
|
+
### Example
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
const result = await context.run("check something", () => ...);
|
|
113
|
+
if (result.cancel) await context.cancel();
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## context.createWebhook
|
|
119
|
+
|
|
120
|
+
Creates a reusable webhook URL for external systems.
|
|
121
|
+
|
|
122
|
+
### Example
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
const { webhookUrl, eventId } = await context.createWebhook("create webhook");
|
|
126
|
+
// Use webhookUrl with an external service
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## context.invoke
|
|
132
|
+
|
|
133
|
+
Invokes another workflow (must be served under the same `serveMany`) and waits for its completion.
|
|
134
|
+
|
|
135
|
+
### Key parameters
|
|
136
|
+
|
|
137
|
+
- `workflow`: the workflow definition.
|
|
138
|
+
- `body`: becomes `requestPayload` of invoked workflow.
|
|
139
|
+
- `headers`: forwarded headers.
|
|
140
|
+
- `workflowRunId`: optional override.
|
|
141
|
+
- `retries`, `retryDelay`, `flowControl`: control invocation retry strategy.
|
|
142
|
+
|
|
143
|
+
### Example
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
const { body, isFailed, isCanceled } = await context.invoke("invoke child", {
|
|
147
|
+
workflow: childWorkflow,
|
|
148
|
+
body: { id: 123 },
|
|
149
|
+
headers: { foo: "bar" },
|
|
150
|
+
retries: 2,
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## context.notify
|
|
157
|
+
|
|
158
|
+
Notifies waiting workflows created via `context.waitForEvent`.
|
|
159
|
+
|
|
160
|
+
### Example
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
const { notifyResponse } = await context.notify("notify step", "order-updated", {
|
|
164
|
+
status: "shipped",
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`notifyResponse` lists all workflows resumed by this event.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## context.run
|
|
173
|
+
|
|
174
|
+
Runs custom synchronous or async logic as a step. Values must be JSON‑serializable.
|
|
175
|
+
|
|
176
|
+
### Example
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
const user = await context.run("load user", () => getUser());
|
|
180
|
+
|
|
181
|
+
await context.run("process user", () => process(user));
|
|
182
|
+
|
|
183
|
+
// Running in parallel
|
|
184
|
+
const a = context.run("step A", () => foo());
|
|
185
|
+
const b = context.run("step B", () => bar());
|
|
186
|
+
await Promise.all([a, b]);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Pitfalls
|
|
190
|
+
|
|
191
|
+
- Returned class instances lose methods due to serialization. Rehydrate via `Object.assign(new Class(), data)`.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## context.sleep
|
|
196
|
+
|
|
197
|
+
Pauses workflow execution for a duration. String or numeric seconds.
|
|
198
|
+
|
|
199
|
+
### Example
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
await context.sleep("wait 1 day", "1d");
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## context.sleepUntil
|
|
208
|
+
|
|
209
|
+
Pauses execution until a specific `Date`, timestamp, or parseable string.
|
|
210
|
+
|
|
211
|
+
### Example
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
const ts = new Date(Date.now() + 1000 * 60 * 60);
|
|
215
|
+
await context.sleepUntil("wait until", ts);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## context.waitForEvent
|
|
221
|
+
|
|
222
|
+
Waits for an event (triggered by `context.notify`) or until timeout.
|
|
223
|
+
|
|
224
|
+
### Example
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
const { eventData, timeout } = await context.waitForEvent("wait for update", "order-updated", {
|
|
228
|
+
timeout: "2h",
|
|
229
|
+
});
|
|
230
|
+
```
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
This documentation explains how to use `serve()` to expose workflows as HTTP endpoints.
|
|
2
|
+
|
|
3
|
+
## Core Concept
|
|
4
|
+
|
|
5
|
+
`serve()` turns an async route function into a workflow endpoint. When a request arrives, a workflow run is created, and the route function defines the execution logic using `context.run()`.
|
|
6
|
+
|
|
7
|
+
### Full Example With Inline Comments
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { serve } from "@upstash/workflow/nextjs";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import { Client, Receiver } from "@upstash/qstash";
|
|
13
|
+
import { loggingMiddleware } from "@upstash/workflow";
|
|
14
|
+
|
|
15
|
+
type InitialPayload = { foo: string; bar: number };
|
|
16
|
+
|
|
17
|
+
const payloadSchema = z.object({ foo: z.string(), bar: z.number() });
|
|
18
|
+
|
|
19
|
+
export const { POST } = serve<InitialPayload>(
|
|
20
|
+
async (context) => {
|
|
21
|
+
const payload = context.requestPayload;
|
|
22
|
+
await context.run("step-1", async () => `hello ${payload.foo}`);
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
// Runs when the workflow fails after all retries
|
|
26
|
+
failureFunction: async ({ context, failStatus, failResponse, failHeaders, failStack }) =>
|
|
27
|
+
console.error(failResponse),
|
|
28
|
+
|
|
29
|
+
// Hooks for step lifecycle, run lifecycle, and debug events
|
|
30
|
+
middlewares: [loggingMiddleware],
|
|
31
|
+
|
|
32
|
+
// Manually parse the initial request payload before workflow execution
|
|
33
|
+
initialPayloadParser: (raw) => JSON.parse(raw),
|
|
34
|
+
|
|
35
|
+
// Automatically validate + parse the request payload using Zod
|
|
36
|
+
schema: payloadSchema,
|
|
37
|
+
|
|
38
|
+
// Override the full URL used to schedule subsequent workflow steps
|
|
39
|
+
url: "https://myapp.com/api/workflow",
|
|
40
|
+
|
|
41
|
+
// Override only the base portion of the inferred URL (keeps the route path)
|
|
42
|
+
baseUrl: "https://proxy-url.com",
|
|
43
|
+
|
|
44
|
+
// Provide a custom QStash client
|
|
45
|
+
qstashClient: new Client({ token: process.env.QSTASH_TOKEN! }),
|
|
46
|
+
|
|
47
|
+
// Provide a custom QStash Receiver for verifying that requests come from QStash
|
|
48
|
+
receiver: new Receiver({
|
|
49
|
+
currentSigningKey: process.env.QSTASH_CURRENT_SIGNING_KEY!,
|
|
50
|
+
nextSigningKey: process.env.QSTASH_NEXT_SIGNING_KEY!,
|
|
51
|
+
}),
|
|
52
|
+
|
|
53
|
+
// Override environment variables available inside workflow execution
|
|
54
|
+
env: {
|
|
55
|
+
QSTASH_URL: "https://qstash.upstash.io",
|
|
56
|
+
QSTASH_TOKEN: process.env.QSTASH_TOKEN!,
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
// Output detailed execution logs to stdout
|
|
60
|
+
verbose: true,
|
|
61
|
+
|
|
62
|
+
// Disable anonymous telemetry for this workflow endpoint
|
|
63
|
+
disableTelemetry: true,
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Common Pitfalls
|
|
69
|
+
|
|
70
|
+
- **Incorrect URL inference** behind proxies or local tunnels—set `url` or `baseUrl`.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Flow Control
|
|
2
|
+
|
|
3
|
+
Flow Control defines how many workflow steps may run or start within a given time, ensuring predictable load and preventing overload of internal or third‑party systems. It applies per **flow control key**, allowing steps across different workflow runs to share the same limits.
|
|
4
|
+
|
|
5
|
+
This skill documents:
|
|
6
|
+
|
|
7
|
+
- parallelism
|
|
8
|
+
- rate and period
|
|
9
|
+
- monitoring
|
|
10
|
+
- common behaviors and pitfalls
|
|
11
|
+
|
|
12
|
+
## Core Concepts
|
|
13
|
+
|
|
14
|
+
### Flow Control Key
|
|
15
|
+
|
|
16
|
+
A string identifier grouping related workflow steps under shared limits.
|
|
17
|
+
All steps triggered with the same key share the same concurrency and rate budget.
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
const client = new Client({ token: "<QSTASH_TOKEN>" });
|
|
21
|
+
|
|
22
|
+
await client.trigger({
|
|
23
|
+
url: "https://<YOUR_ENDPOINT>",
|
|
24
|
+
flowControl: {
|
|
25
|
+
key: "user-onboarding", // Groups steps under this key
|
|
26
|
+
parallelism: 5, // max concurrent steps
|
|
27
|
+
rate: 20, // max starts per period
|
|
28
|
+
period: "1m", // time window
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Parallelism
|
|
34
|
+
|
|
35
|
+
Controls **how many steps may run concurrently**.
|
|
36
|
+
Works like a token bucket: each running step consumes one token; when it finishes, the token is released.
|
|
37
|
+
|
|
38
|
+
- If tokens are available → step starts immediately.
|
|
39
|
+
- If no tokens → step enters the waitlist.
|
|
40
|
+
- Token handoff is **not FIFO**; later steps may start earlier.
|
|
41
|
+
|
|
42
|
+
### Example Behavior
|
|
43
|
+
|
|
44
|
+
- `parallelism = 3` → at most 3 steps run at the same time.
|
|
45
|
+
- Step 4 waits until one of the first 3 completes.
|
|
46
|
+
|
|
47
|
+
Parallelism affects **execution concurrency**, not rate‑of‑start per time window.
|
|
48
|
+
|
|
49
|
+
## Rate & Period
|
|
50
|
+
|
|
51
|
+
Controls **how many steps may START within a defined time window**.
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
flowControl: {
|
|
55
|
+
key: "billing-jobs",
|
|
56
|
+
rate: 2, // allow 2 starts
|
|
57
|
+
period: "10s", // every 10 seconds
|
|
58
|
+
parallelism: 1, // can be combined
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Behavior:
|
|
63
|
+
|
|
64
|
+
- First `rate` steps in each period start immediately.
|
|
65
|
+
- Additional steps wait until the next window.
|
|
66
|
+
- Execution duration **does not** count toward the period; only start time matters.
|
|
67
|
+
|
|
68
|
+
This is rate limiting, not concurrency control.
|
|
69
|
+
|
|
70
|
+
## Combining Rate + Parallelism
|
|
71
|
+
|
|
72
|
+
Both limits apply **independently**.
|
|
73
|
+
A step must satisfy _both_ to run.
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
|
|
77
|
+
- `rate = 3 per minute`
|
|
78
|
+
- `parallelism = 7`
|
|
79
|
+
|
|
80
|
+
Even if concurrency slots are free, steps may be delayed by the rate window.
|
|
81
|
+
Even if rate window is open, steps may be delayed by concurrency.
|
|
82
|
+
|
|
83
|
+
This enables predictable load patterns.
|
|
84
|
+
|
|
85
|
+
## Monitoring
|
|
86
|
+
|
|
87
|
+
Flow control queues and waitlists are visible from:
|
|
88
|
+
|
|
89
|
+
- Console → **FlowControl** tab (waitlist size per key)
|
|
90
|
+
- REST API:
|
|
91
|
+
- List all keys
|
|
92
|
+
- Get details for one key
|
|
93
|
+
|
|
94
|
+
Useful for diagnosing bottlenecks, long queues, or misconfigured limits.
|
|
95
|
+
|
|
96
|
+
## Important Behaviors & Pitfalls
|
|
97
|
+
|
|
98
|
+
### Limits are stored on each step
|
|
99
|
+
|
|
100
|
+
If you deploy new limits, previously published steps keep their original configuration.
|
|
101
|
+
|
|
102
|
+
### No per‑step config (mostly)
|
|
103
|
+
|
|
104
|
+
All steps inherit the workflow‑run’s flowControl block.
|
|
105
|
+
Exceptions:
|
|
106
|
+
|
|
107
|
+
- `context.call` – may define a separate key to isolate API throttling.
|
|
108
|
+
- `context.invoke` – spawns a new workflow run with its own flowControl.
|
|
109
|
+
|
|
110
|
+
To isolate heavy or sensitive steps, move them into a separate workflow and invoke them.
|
|
111
|
+
|
|
112
|
+
### Waitlist order is not guaranteed
|
|
113
|
+
|
|
114
|
+
A later step may receive a token before an earlier one.
|
|
115
|
+
Do not rely on ordering.
|
|
116
|
+
|
|
117
|
+
### Queueing is automatic
|
|
118
|
+
|
|
119
|
+
Exceeding limits never rejects steps. Everything is eventually executed.
|
|
120
|
+
|
|
121
|
+
## Full Example
|
|
122
|
+
|
|
123
|
+
Demonstrates defining all parameters together and how they interact.
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
import { Client } from "@upstash/workflow";
|
|
127
|
+
|
|
128
|
+
const client = new Client({ token: "<QSTASH_TOKEN>" });
|
|
129
|
+
|
|
130
|
+
await client.trigger({
|
|
131
|
+
url: "https://<YOUR_WORKFLOW_ENDPOINT>/process",
|
|
132
|
+
flowControl: {
|
|
133
|
+
key: "media-processing", // Shared grouping key
|
|
134
|
+
parallelism: 4, // Max 4 at the same time
|
|
135
|
+
rate: 10, // Max 10 starts
|
|
136
|
+
period: "60s", // in 60 seconds
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
This configuration:
|
|
142
|
+
|
|
143
|
+
- ensures no more than 4 processing tasks run concurrently
|
|
144
|
+
- ensures no more than 10 tasks start per minute
|
|
145
|
+
- queues everything automatically beyond those limits
|