From 033148437cb515a79e05e6095954d96f2de6a5c9 Mon Sep 17 00:00:00 2001 From: Matt Silverlock Date: Tue, 1 Apr 2025 18:53:21 -0400 Subject: [PATCH 01/12] workflows: new docs --- ...04-07-workflows-human-in-the-loop copy.mdx | 20 ++++++++++++++++ ...2025-04-07-workflows-human-in-the-loop.mdx | 23 +++++++++++++++++++ .../workflows/build/events-and-parameters.mdx | 7 +++++- .../workflows/build/human-in-the-loop.mdx | 9 ++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop copy.mdx create mode 100644 src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop.mdx create mode 100644 src/content/docs/workflows/build/human-in-the-loop.mdx diff --git a/src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop copy.mdx b/src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop copy.mdx new file mode 100644 index 00000000000000..92830a372fbd9a --- /dev/null +++ b/src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop copy.mdx @@ -0,0 +1,20 @@ +--- +title: Workflows is now Generally Available +description: Workflows is now GA - ship Workflows that you can rely on in production. + - workflows + - workers +date: 2025-04-08T13:00:00Z +--- + +import { Render, PackageManagers, TypeScriptExample } from "~/components" + +[Workflows](/workflows/) is now _Generally Available_ (or "GA"): in short, it's ready for production workloads. + +* Increased concurrency +* A new `waitForEvent` API +* Improved observability, including new CPU time metrics that allow you to better +* Support for `vitest` and testing integrations. + +Workflows also supports the [increased CPU limits](/changelog/2025-03-25-higher-cpu-limits/) that apply to Workers, allowing you to run more CPU-intensive tasks (up to 5 minutes of CPU time per instance), not including the time spent waiting on network calls, AI models, or other I/O bound tasks. + +Read the [GA announcement blog](https://blog.cloudflare.com/workflows-is-now-generally-available/) to learn more. diff --git a/src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop.mdx b/src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop.mdx new file mode 100644 index 00000000000000..173a0ceba390b3 --- /dev/null +++ b/src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop.mdx @@ -0,0 +1,23 @@ +--- +title: Workflows now support human-in-the-loop events +description: You can now use the new waitForEvent API in Workflows to send data to running Workflows. + - workflows + - workers +date: 2025-04-07T13:00:00Z +--- + +import { Render, PackageManagers, TypeScriptExample } from "~/components" + +You can now have [Workflows](/workflows/) wait for events and data to be sent to them, enabling human-in-the-the-loop interactions, such as approving or rejecting a request, directly handling webhooks from other systems, or pushing event data to a Workflow while it's running. + + + + + +```ts +import { Workflow, WorkflowEvent } from "cloudflare:workflows"; + + +``` + + diff --git a/src/content/docs/workflows/build/events-and-parameters.mdx b/src/content/docs/workflows/build/events-and-parameters.mdx index 143632df05b212..6b06e6646eb971 100644 --- a/src/content/docs/workflows/build/events-and-parameters.mdx +++ b/src/content/docs/workflows/build/events-and-parameters.mdx @@ -14,10 +14,11 @@ Events are a powerful part of a Workflow, as you often want a Workflow to act on ## Pass parameters to a Workflow -You can pass parameters to a Workflow in two ways: +You can pass parameters to a Workflow in three ways: * As an optional argument to the `create` method on a [Workflow binding](/workers/wrangler/commands/#trigger) when triggering a Workflow from a Worker. * Via the `--params` flag when using the `wrangler` CLI to trigger a Workflow. +* Via the `step.waitForEvent` API, which allows a Workflow instance to wait for an event (and optional data) to be received while it is running. You can pass any JSON-serializable object as a parameter. @@ -60,6 +61,10 @@ npx wrangler@latest workflows trigger workflows-starter '{"some":"data"}' 🚀 Workflow instance "57c7913b-8e1d-4a78-a0dd-dce5a0b7aa30" has been queued successfully ``` +### Wait for events + +TODO - + ## TypeScript and type parameters By default, the `WorkflowEvent` passed to the `run` method of your Workflow definition has a type that conforms to the following, with `payload` (your data), `timestamp`, and `instanceId` properties: diff --git a/src/content/docs/workflows/build/human-in-the-loop.mdx b/src/content/docs/workflows/build/human-in-the-loop.mdx new file mode 100644 index 00000000000000..421a1db8de2ddc --- /dev/null +++ b/src/content/docs/workflows/build/human-in-the-loop.mdx @@ -0,0 +1,9 @@ +--- +title: Human in the loop +pcx_content_type: concept +sidebar: + order: 7 +--- + +import { WranglerConfig, TypeScriptExample } from "~/components"; + From f3d08fbc16b173c5dc581ee200f44eb186037926 Mon Sep 17 00:00:00 2001 From: Matt Silverlock Date: Wed, 2 Apr 2025 15:12:39 -0400 Subject: [PATCH 02/12] update --- .../workflows/2025-04-07-workflows-ga.mdx | 38 +++++++++++++++++++ ...04-07-workflows-human-in-the-loop copy.mdx | 20 ---------- ...2025-04-07-workflows-human-in-the-loop.mdx | 23 ----------- 3 files changed, 38 insertions(+), 43 deletions(-) create mode 100644 src/content/changelog/workflows/2025-04-07-workflows-ga.mdx delete mode 100644 src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop copy.mdx delete mode 100644 src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop.mdx diff --git a/src/content/changelog/workflows/2025-04-07-workflows-ga.mdx b/src/content/changelog/workflows/2025-04-07-workflows-ga.mdx new file mode 100644 index 00000000000000..24749f5b4b4efc --- /dev/null +++ b/src/content/changelog/workflows/2025-04-07-workflows-ga.mdx @@ -0,0 +1,38 @@ +--- +title: Workflows is now Generally Available +description: Workflows is now GA - ship Workflows that you can rely on in production. + - workflows + - workers +date: 2025-04-07T13:00:00Z +--- + +import { Render, PackageManagers, TypeScriptExample } from "~/components" + +[Workflows](/workflows/) is now _Generally Available_ (or "GA"): in short, it's ready for production workloads. Alongside marking Workflows as GA, we've introduced a number of changes during the beta period, including: + +* A new `waitForEvent` API that allows a Workflow to wait for an event to occur before continuing execution. +* Increased concurrency: you can [run up to 4,500 Workflow instances](/changelog/2025-02-25-workflows-concurrency-increased/) concurrently (and this will continue to grow) +* Improved observability, including new CPU time metrics that allow you to better understand which Workflow instances are consuming the most resources and/or contributing to your bill. +* Support for `vitest` for testing Workflows locally and in CI/CD pipelines. + +Workflows also supports the new [increased CPU limits](/changelog/2025-03-25-higher-cpu-limits/) that apply to Workers, allowing you to run more CPU-intensive tasks (up to 5 minutes of CPU time per instance), not including the time spent waiting on network calls, AI models, or other I/O bound tasks. + +#### Human-in-the-loop + +The new `step.waitForEvent` API allows a Workflow instance to wait on events and data, enabling human-in-the-the-loop interactions, such as approving or rejecting a request, directly handling webhooks from other systems, or pushing event data to a Workflow while it's running. + +Because Workflows are just code, you can conditionally execute code based on the result of a `waitForEvent` call, and/or call `waitForEvent` multiple times in a single Workflow based on what the Workflow needs. + +For example, if you wanted to implement a human-in-the-loop approval process, you could use `waitForEvent` to wait for a user to approve or reject a request, and then conditionally execute code based on the result. + + + +```ts +import { Workflow, WorkflowEvent } from "cloudflare:workflows"; + + +``` + + + +Read the [GA announcement blog](https://blog.cloudflare.com/workflows-is-now-generally-available/) to learn more about what landed as part of the Workflows GA. diff --git a/src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop copy.mdx b/src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop copy.mdx deleted file mode 100644 index 92830a372fbd9a..00000000000000 --- a/src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop copy.mdx +++ /dev/null @@ -1,20 +0,0 @@ ---- -title: Workflows is now Generally Available -description: Workflows is now GA - ship Workflows that you can rely on in production. - - workflows - - workers -date: 2025-04-08T13:00:00Z ---- - -import { Render, PackageManagers, TypeScriptExample } from "~/components" - -[Workflows](/workflows/) is now _Generally Available_ (or "GA"): in short, it's ready for production workloads. - -* Increased concurrency -* A new `waitForEvent` API -* Improved observability, including new CPU time metrics that allow you to better -* Support for `vitest` and testing integrations. - -Workflows also supports the [increased CPU limits](/changelog/2025-03-25-higher-cpu-limits/) that apply to Workers, allowing you to run more CPU-intensive tasks (up to 5 minutes of CPU time per instance), not including the time spent waiting on network calls, AI models, or other I/O bound tasks. - -Read the [GA announcement blog](https://blog.cloudflare.com/workflows-is-now-generally-available/) to learn more. diff --git a/src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop.mdx b/src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop.mdx deleted file mode 100644 index 173a0ceba390b3..00000000000000 --- a/src/content/changelog/workflows/2025-04-07-workflows-human-in-the-loop.mdx +++ /dev/null @@ -1,23 +0,0 @@ ---- -title: Workflows now support human-in-the-loop events -description: You can now use the new waitForEvent API in Workflows to send data to running Workflows. - - workflows - - workers -date: 2025-04-07T13:00:00Z ---- - -import { Render, PackageManagers, TypeScriptExample } from "~/components" - -You can now have [Workflows](/workflows/) wait for events and data to be sent to them, enabling human-in-the-the-loop interactions, such as approving or rejecting a request, directly handling webhooks from other systems, or pushing event data to a Workflow while it's running. - - - - - -```ts -import { Workflow, WorkflowEvent } from "cloudflare:workflows"; - - -``` - - From 5286ca703fd8eebae33dd4c4f7a9d97daed804fa Mon Sep 17 00:00:00 2001 From: Matt Silverlock Date: Wed, 2 Apr 2025 15:37:41 -0400 Subject: [PATCH 03/12] remove beta badge --- src/content/docs/workflows/index.mdx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/content/docs/workflows/index.mdx b/src/content/docs/workflows/index.mdx index 665c376a83c668..4c0a22bc4bc2c6 100644 --- a/src/content/docs/workflows/index.mdx +++ b/src/content/docs/workflows/index.mdx @@ -5,8 +5,6 @@ type: overview pcx_content_type: overview sidebar: order: 1 - badge: - text: Beta head: - tag: title content: Overview From dd0c5c3d6db2fe5999b0889b9d93a51c241da4e2 Mon Sep 17 00:00:00 2001 From: Matt Silverlock Date: Wed, 2 Apr 2025 15:39:12 -0400 Subject: [PATCH 04/12] limits --- src/content/docs/workflows/build/workers-api.mdx | 10 ++-------- .../docs/workflows/get-started/cli-quick-start.mdx | 8 -------- src/content/docs/workflows/get-started/guide.mdx | 8 -------- src/content/docs/workflows/reference/limits.mdx | 12 +++++------- 4 files changed, 7 insertions(+), 31 deletions(-) diff --git a/src/content/docs/workflows/build/workers-api.mdx b/src/content/docs/workflows/build/workers-api.mdx index 3f5499b8c7744e..4efb0c74ba9a03 100644 --- a/src/content/docs/workflows/build/workers-api.mdx +++ b/src/content/docs/workflows/build/workers-api.mdx @@ -84,7 +84,7 @@ When returning state from a `step`, ensure that the object you return is _serial Primitive types like `string`, `number`, and `boolean`, along with composite structures such as `Array` and `Object` (provided they only contain serializable values), can be serialized. -Objects that include `Function` or `Symbol` types, and objects with circular references, cannot be serialized and the Workflow instance will throw an error if objects with those types is returned. +Objects that include `Function` or `Symbol` types, and objects with circular references, cannot be serialized and the Workflow instance will throw an error if objects with those types is returned. ::: @@ -133,12 +133,6 @@ Refer to the [documentation on sleeping and retrying](/workflows/build/sleeping- ## Call Workflows from Workers -:::note[Workflows beta] - -Workflows currently requires you to bind to a Workflow via the [Wrangler configuration file](/workers/wrangler/configuration/), and does not yet support bindings via the Workers dashboard. - -::: - Workflows exposes an API directly to your Workers scripts via the [bindings](/workers/runtime-apis/bindings/#what-is-a-binding) concept. Bindings allow you to securely call a Workflow without having to manage API keys or clients. You can bind to a Workflow by defining a `[[workflows]]` binding within your Wrangler configuration. @@ -286,7 +280,7 @@ This is useful when you are scheduling multiple instances at once. A call to `cr * `batch` - list of Options to pass when creating an instance, including a user-provided ID and payload parameters. -Each element of the `batch` list is expected to the +Each element of the `batch` list is expected to the ```ts // Create a new batch of 3 Workflow instances, each with its own ID and pass params to the Workflow instances diff --git a/src/content/docs/workflows/get-started/cli-quick-start.mdx b/src/content/docs/workflows/get-started/cli-quick-start.mdx index d8573317efc6e6..ad1ab347278b35 100644 --- a/src/content/docs/workflows/get-started/cli-quick-start.mdx +++ b/src/content/docs/workflows/get-started/cli-quick-start.mdx @@ -9,14 +9,6 @@ sidebar: import { Render, PackageManagers, WranglerConfig } from "~/components" -:::note - -Workflows is in **public beta**, and any developer with a [free or paid Workers plan](/workers/platform/pricing/#workers) can start using Workflows immediately. - -To learn more about Workflows and how it works, read [the beta announcement blog](https://blog.cloudflare.com/building-workflows-durable-execution-on-workers). - -::: - Workflows allow you to build durable, multi-step applications using the Workers platform. A Workflow can automatically retry, persist state, run for hours or days, and coordinate between third-party APIs. You can build Workflows to post-process file uploads to [R2 object storage](/r2/), automate generation of [Workers AI](/workers-ai/) embeddings into a [Vectorize](/vectorize/) vector database, or to trigger user lifecycle emails using your favorite email API. diff --git a/src/content/docs/workflows/get-started/guide.mdx b/src/content/docs/workflows/get-started/guide.mdx index aa3b703db5ae4d..c29d39d90b5fc2 100644 --- a/src/content/docs/workflows/get-started/guide.mdx +++ b/src/content/docs/workflows/get-started/guide.mdx @@ -9,14 +9,6 @@ sidebar: import { Render, PackageManagers, WranglerConfig } from "~/components" -:::note - -Workflows is in **public beta**, and any developer with a [free or paid Workers plan](/workers/platform/pricing/#workers) can start using Workflows immediately. - -To learn more about Workflows and how it works, read [the beta announcement blog](https://blog.cloudflare.com/building-workflows-durable-execution-on-workers). - -::: - Workflows allow you to build durable, multi-step applications using the Workers platform. A Workflow can automatically retry, persist state, run for hours or days, and coordinate between third-party APIs. You can build Workflows to post-process file uploads to [R2 object storage](/r2/), automate generation of [Workers AI](/workers-ai/) embeddings into a [Vectorize](/vectorize/) vector database, or to trigger user lifecycle emails using your favorite email API. diff --git a/src/content/docs/workflows/reference/limits.mdx b/src/content/docs/workflows/reference/limits.mdx index f92128d6bf6a28..c85be2585d9b45 100644 --- a/src/content/docs/workflows/reference/limits.mdx +++ b/src/content/docs/workflows/reference/limits.mdx @@ -22,17 +22,15 @@ Many limits are inherited from those applied to Workers scripts and as documente | Maximum event [payload size](/workflows/build/events-and-parameters/) | 1MiB (2^20 bytes) | 1MiB (2^20 bytes) | | Maximum state that can be persisted per Workflow instance | 100MB | 1GB | | Maximum length of a Workflow ID [^4] | 64 characters | 64 characters | -| Maximum `step.sleep` duration | 365 days (1 year) [^1] | 365 days (1 year) [^1] | -| Maximum steps per Workflow [^5] | 1024 [^1] | 1024 [^1] | +| Maximum `step.sleep` duration | 365 days (1 year) | 365 days (1 year) | +| Maximum steps per Workflow [^5] | 1024 | 1024 | | Maximum Workflow executions | 100,000 per day [shared with Workers daily limit](/workers/platform/limits/#worker-limits) | Unlimited | -| Concurrent Workflow instances (executions) per account | 25 | 4500 [^1] | -| Maximum Workflow instance creation rate | 100 per 10 seconds [^1][^6] | 100 per 10 seconds [^1][^6] | -| Maximum number of [queued instances](/workflows/observability/metrics-analytics/#event-types) | 10,000 [^1] | 100,000 [^1] | +| Concurrent Workflow instances (executions) per account | 25 | 4500 | +| Maximum Workflow instance creation rate | 100 per 10 seconds [^6] | 100 per 10 seconds [^6] | +| Maximum number of [queued instances](/workflows/observability/metrics-analytics/#event-types) | 10,000 | 100,000 | | Retention limit for completed Workflow state | 3 days | 30 days [^2] | | Maximum length of a Workflow ID [^4] | 64 characters | 64 characters | -[^1]: This limit will be reviewed and revised during the open beta for Workflows. Follow the [Workflows changelog](/workflows/reference/changelog/) for updates. - [^2]: Workflow state and logs will be retained for 3 days on the Workers Free plan and for 7 days on the Workers Paid plan. [^3]: A Workflow instance can run forever, as long as each step does not take more than the CPU time limit and the maximum number of steps per Workflow is not reached. From 81fa8f401fbd96c03b201f6552a98b796a061878 Mon Sep 17 00:00:00 2001 From: Matt Silverlock Date: Wed, 2 Apr 2025 17:00:04 -0400 Subject: [PATCH 05/12] pricin --- .../docs/workflows/reference/pricing.mdx | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/content/docs/workflows/reference/pricing.mdx b/src/content/docs/workflows/reference/pricing.mdx index be45f5a44ddc98..e475ddb4bb88e3 100644 --- a/src/content/docs/workflows/reference/pricing.mdx +++ b/src/content/docs/workflows/reference/pricing.mdx @@ -14,20 +14,52 @@ Workflows is included in both the Free and Paid [Workers plans](/workers/platfor ::: -Workflows pricing is identical to [Workers Standard pricing](/workers/platform/pricing/#workers) and are billed on two dimensions: +Workflows pricing is identical to [Workers Standard pricing](/workers/platform/pricing/#workers) and are billed on three dimensions: * **CPU time**: the total amount of compute (measured in milliseconds) consumed by a given Workflow. * **Requests** (invocations): the number of Workflow invocations. [Subrequests](/workers/platform/limits/#subrequests) made from a Workflow do not incur additional request costs. +* **Storage**: the total amount of storage (measured in GB) persisted by your Workflows. A Workflow that is waiting on a response to an API call, paused as a result of calling `step.sleep`, or otherwise idle, does not incur CPU time. +### Workflows Pricing + +| Unit | Workers Free | Workers Paid | +|------|--------------|--------------| +| Requests (millions) | 100,000 per day ([shared with Workers requests](/workers/platform/pricing/#workers)| 10 million included per month + $0.30 per additional million | +| CPU time (ms) | 10 milliseconds of CPU time per invocation | 30 million CPU milliseconds included per month + $0.02 per additional million CPU milliseconds | +| Storage (GB-mo) | 1GB | 1GB included per month + $0.20/ GB-month | + +::note[CPU limits] + +You can increase the CPU limit available to your Workflow instances up to 5 minutes per Workflow by [setting the `limits.cpu_ms` property](/workers/wrangler/configuration/#limits) in your Wrangler configuration. + +::: + +### Storage Usage + +:::Note + +Storage billing for Workflows will go live on September 15th, 2025. + +::: + +Storage is billed using gigabyte-month (GB-month) as the billing metric, identical to [Durable Objects SQL storage](/durable-objects/platform/pricing/#sqlite-storage-backend). A GB-month is calculated by averaging the peak storage per day over a billing period (30 days). + +* Storage is calculated across all instances, and includes running, errored, sleeping and completed instances. +* By default, instance state is retained for [3 days on the Free plan](/workflows/reference/limits/) and [7 days on the Paid plan](/workflows/reference/limits/). +* When creating a Workflow instance, you can set a shorter state retention period if you do not need to retain state for errored or completed Workflows. +* Deleting instances via the [Workers API](/workflows/build/workers-api/), [wrangler CLI](/workers/wrangler/commands/#workflows), REST API or dashboard will free up storage. Note that it may take a few minutes for storage limits to update. + +An instance that attempts to store state when your have reached the storage limit on the Free plan will cause an error to be thrown. + ## Frequently Asked Questions Frequently asked questions related to Workflows pricing: ### Are there additional costs for Workflows? -No. Workflows are priced based on the same compute (CPU time) and requests (invocations) as Workers. +No. Workflows are priced based on the same compute (CPU time), requests (invocations) as Workers, as well as storage (state from a Workflow). ### Are Workflows available on the [Workers Free](/workers/platform/pricing/#workers) plan? From b0b0e87c4025c72179988ea98227fb0d497015aa Mon Sep 17 00:00:00 2001 From: Matt Silverlock Date: Thu, 3 Apr 2025 09:50:57 -0400 Subject: [PATCH 06/12] waitForEvent more --- .../workflows/build/events-and-parameters.mdx | 22 +++++++++++++++- ...he-loop.mdx => send-data-to-workflows.mdx} | 3 ++- .../docs/workflows/build/workers-api.mdx | 25 +++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) rename src/content/docs/workflows/build/{human-in-the-loop.mdx => send-data-to-workflows.mdx} (74%) diff --git a/src/content/docs/workflows/build/events-and-parameters.mdx b/src/content/docs/workflows/build/events-and-parameters.mdx index 6b06e6646eb971..49b0572efb39dd 100644 --- a/src/content/docs/workflows/build/events-and-parameters.mdx +++ b/src/content/docs/workflows/build/events-and-parameters.mdx @@ -30,6 +30,8 @@ Store state durably by returning it from your `step.do` callbacks. ::: + + ```ts export default { async fetch(req: Request, env: Env) { @@ -52,6 +54,8 @@ export default { }; ``` + + To pass parameters via the `wrangler` command-line interface, pass a JSON string as the second parameter to the `workflows trigger` sub-command: ```sh @@ -63,7 +67,23 @@ npx wrangler@latest workflows trigger workflows-starter '{"some":"data"}' ### Wait for events -TODO - +A running Workflow can wait for an event (or events) by calling `step.waitForEvent`. + + + +```ts +export class MyWorkflow extends WorkflowEntrypoint { + async run(event: WorkflowEvent, step: WorkflowStep) { + // TODO + // + // TODO + } +} +``` + + + +Visit the [guide on sending data to Workflows] to learn about how to pass event data to a running Workflow, including via HTTP (webhooks) and/or Workers bindings. ## TypeScript and type parameters diff --git a/src/content/docs/workflows/build/human-in-the-loop.mdx b/src/content/docs/workflows/build/send-data-to-workflows.mdx similarity index 74% rename from src/content/docs/workflows/build/human-in-the-loop.mdx rename to src/content/docs/workflows/build/send-data-to-workflows.mdx index 421a1db8de2ddc..f63f91113141da 100644 --- a/src/content/docs/workflows/build/human-in-the-loop.mdx +++ b/src/content/docs/workflows/build/send-data-to-workflows.mdx @@ -1,5 +1,5 @@ --- -title: Human in the loop +title: Send data to running Workflows pcx_content_type: concept sidebar: order: 7 @@ -7,3 +7,4 @@ sidebar: import { WranglerConfig, TypeScriptExample } from "~/components"; +### \ No newline at end of file diff --git a/src/content/docs/workflows/build/workers-api.mdx b/src/content/docs/workflows/build/workers-api.mdx index 4efb0c74ba9a03..6040efcb4bb02b 100644 --- a/src/content/docs/workflows/build/workers-api.mdx +++ b/src/content/docs/workflows/build/workers-api.mdx @@ -404,6 +404,31 @@ Terminate a Workflow instance. * terminate(): Promise<void> +### sendEvent + +[Send an event]() to a running Workflow instance. + +* sendEvent(): Promise<void> + + * `options` - the event `type` and `payload` to send to the Workflow instance. The `type` must match the `type` in + +Return `void` on success; throws an exception if the Workflow is not running or is an errored state. + + + +```ts +export class MyWorkflow extends WorkflowEntrypoint { + async run(event: WorkflowEvent, step: WorkflowStep) { + // TODO + // + // TODO + } +} +``` + + + + ### InstanceStatus Details the status of a Workflow instance. From 097e4ca30b7da88b1020340b59d5de4977207af7 Mon Sep 17 00:00:00 2001 From: Matt Silverlock Date: Thu, 3 Apr 2025 15:06:10 -0400 Subject: [PATCH 07/12] hidden: true --- .../workflows/2025-04-07-workflows-ga.mdx | 1 + .../workflows/build/events-and-parameters.mdx | 25 ++++++++++++++++--- .../build/send-data-to-workflows.mdx | 10 -------- .../docs/workflows/build/workers-api.mdx | 8 ++++++ 4 files changed, 30 insertions(+), 14 deletions(-) delete mode 100644 src/content/docs/workflows/build/send-data-to-workflows.mdx diff --git a/src/content/changelog/workflows/2025-04-07-workflows-ga.mdx b/src/content/changelog/workflows/2025-04-07-workflows-ga.mdx index 24749f5b4b4efc..3db26b4aad7364 100644 --- a/src/content/changelog/workflows/2025-04-07-workflows-ga.mdx +++ b/src/content/changelog/workflows/2025-04-07-workflows-ga.mdx @@ -4,6 +4,7 @@ description: Workflows is now GA - ship Workflows that you can rely on in produc - workflows - workers date: 2025-04-07T13:00:00Z +hidden: true --- import { Render, PackageManagers, TypeScriptExample } from "~/components" diff --git a/src/content/docs/workflows/build/events-and-parameters.mdx b/src/content/docs/workflows/build/events-and-parameters.mdx index 49b0572efb39dd..5803365178fd2c 100644 --- a/src/content/docs/workflows/build/events-and-parameters.mdx +++ b/src/content/docs/workflows/build/events-and-parameters.mdx @@ -12,13 +12,13 @@ When a Workflow is triggered, it can receive an optional event. This event can i Events are a powerful part of a Workflow, as you often want a Workflow to act on data. Because a given Workflow instance executes durably, events are a useful way to provide a Workflow with data that should be immutable (not changing) and/or represents data the Workflow needs to operate on at that point in time. -## Pass parameters to a Workflow +## Pass data to a Workflow You can pass parameters to a Workflow in three ways: * As an optional argument to the `create` method on a [Workflow binding](/workers/wrangler/commands/#trigger) when triggering a Workflow from a Worker. * Via the `--params` flag when using the `wrangler` CLI to trigger a Workflow. -* Via the `step.waitForEvent` API, which allows a Workflow instance to wait for an event (and optional data) to be received while it is running. +* Via the `step.waitForEvent` API, which allows a Workflow instance to wait for an event (and optional data) to be received _while it is running_. You can pass any JSON-serializable object as a parameter. @@ -67,7 +67,25 @@ npx wrangler@latest workflows trigger workflows-starter '{"some":"data"}' ### Wait for events -A running Workflow can wait for an event (or events) by calling `step.waitForEvent`. +A running Workflow can wait for an event (or events) by calling `step.waitForEvent` within the Workflow. + + + +```ts +export class MyWorkflow extends WorkflowEntrypoint { + async run(event: WorkflowEvent, step: WorkflowStep) { + // TODO + // + // TODO + } +} +``` + + + +### Sending events to running workflows + +TODO @@ -83,7 +101,6 @@ export class MyWorkflow extends WorkflowEntrypoint { -Visit the [guide on sending data to Workflows] to learn about how to pass event data to a running Workflow, including via HTTP (webhooks) and/or Workers bindings. ## TypeScript and type parameters diff --git a/src/content/docs/workflows/build/send-data-to-workflows.mdx b/src/content/docs/workflows/build/send-data-to-workflows.mdx deleted file mode 100644 index f63f91113141da..00000000000000 --- a/src/content/docs/workflows/build/send-data-to-workflows.mdx +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Send data to running Workflows -pcx_content_type: concept -sidebar: - order: 7 ---- - -import { WranglerConfig, TypeScriptExample } from "~/components"; - -### \ No newline at end of file diff --git a/src/content/docs/workflows/build/workers-api.mdx b/src/content/docs/workflows/build/workers-api.mdx index 6040efcb4bb02b..479497dca6fde9 100644 --- a/src/content/docs/workflows/build/workers-api.mdx +++ b/src/content/docs/workflows/build/workers-api.mdx @@ -107,6 +107,14 @@ More information about the limits imposed on Workflow can be found in the [Workf ::: +* step.waitForEvent(name: string, options: ): Promise<void> + + * `name` - the name of the step. + * `options` - an object with properties for `type`, which determines which event type this `waitForEvent` call will match on when calling `instance.sendEvent`, and an optional `timeout` property, which defines how long the `waitForEvent` call will block for before throwing a timeout exception. The default timeout is 24 hours. + +Review the documentation on [events and parameters](/workflows/build/events-and-parameters/) to learn how to send events to a running Workflow instance. + + ## WorkflowStepConfig ```ts From cf2a3c8e3cda7c94f25be3a65bc7e52c9ad65ba6 Mon Sep 17 00:00:00 2001 From: Matt Silverlock Date: Thu, 3 Apr 2025 17:44:11 -0400 Subject: [PATCH 08/12] flesh out examples --- .../workflows/build/events-and-parameters.mdx | 30 ++++++++----- .../docs/workflows/build/workers-api.mdx | 44 ++++++++++++++----- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/content/docs/workflows/build/events-and-parameters.mdx b/src/content/docs/workflows/build/events-and-parameters.mdx index 5803365178fd2c..54e2af8ca9f393 100644 --- a/src/content/docs/workflows/build/events-and-parameters.mdx +++ b/src/content/docs/workflows/build/events-and-parameters.mdx @@ -74,15 +74,17 @@ A running Workflow can wait for an event (or events) by calling `step.waitForEve ```ts export class MyWorkflow extends WorkflowEntrypoint { async run(event: WorkflowEvent, step: WorkflowStep) { - // TODO - // - // TODO + // Other steps in your Workflow + let event = await step.waitForEvent("receive invoice paid webhook from Stripe", { type: "stripe-webhook", timeout: "1 hour" }) + // Rest of your Workflow } } ``` +TODO + ### Sending events to running workflows TODO @@ -90,13 +92,21 @@ TODO ```ts -export class MyWorkflow extends WorkflowEntrypoint { - async run(event: WorkflowEvent, step: WorkflowStep) { - // TODO - // - // TODO - } -} +export default { + async fetch(req: Request, env: Env) { + const instanceId = new URL(req.url).searchParams.get("instanceId") + const webhookPayload = await req.json() + + let instance = await env.MY_WORKFLOW.get(instanceId); + // Send our event, with `type` matching the event type defined in + // our step.waitForEvent call + await instance.sendEvent({type: "stripe-webhook", payload: webhookPayload}) + + return Response.json({ + status: await instance.status(), + }); + }, +}; ``` diff --git a/src/content/docs/workflows/build/workers-api.mdx b/src/content/docs/workflows/build/workers-api.mdx index 479497dca6fde9..6fbcc539518f75 100644 --- a/src/content/docs/workflows/build/workers-api.mdx +++ b/src/content/docs/workflows/build/workers-api.mdx @@ -112,8 +112,21 @@ More information about the limits imposed on Workflow can be found in the [Workf * `name` - the name of the step. * `options` - an object with properties for `type`, which determines which event type this `waitForEvent` call will match on when calling `instance.sendEvent`, and an optional `timeout` property, which defines how long the `waitForEvent` call will block for before throwing a timeout exception. The default timeout is 24 hours. -Review the documentation on [events and parameters](/workflows/build/events-and-parameters/) to learn how to send events to a running Workflow instance. + + +```ts +export class MyWorkflow extends WorkflowEntrypoint { + async run(event: WorkflowEvent, step: WorkflowStep) { + // Other steps in your Workflow + let event = await step.waitForEvent("receive invoice paid webhook from Stripe", { type: "stripe-webhook", timeout: "1 hour" }) + // Rest of your Workflow + } +} +``` + + +Review the documentation on [events and parameters](/workflows/build/events-and-parameters/) to learn how to send events to a running Workflow instance. ## WorkflowStepConfig @@ -414,28 +427,39 @@ Terminate a Workflow instance. ### sendEvent -[Send an event]() to a running Workflow instance. +[Send an event](/workflows/build/events-and-parameters/) to a running Workflow instance. * sendEvent(): Promise<void> - * `options` - the event `type` and `payload` to send to the Workflow instance. The `type` must match the `type` in + * `options` - the event `type` and `payload` to send to the Workflow instance. The `type` must match the `type` in the corresponding `waitForEvent` call in your Workflow. Return `void` on success; throws an exception if the Workflow is not running or is an errored state. ```ts -export class MyWorkflow extends WorkflowEntrypoint { - async run(event: WorkflowEvent, step: WorkflowStep) { - // TODO - // - // TODO - } -} +export default { + async fetch(req: Request, env: Env) { + const instanceId = new URL(req.url).searchParams.get("instanceId") + const webhookPayload = await req.json() + + let instance = await env.MY_WORKFLOW.get(instanceId); + // Send our event, with `type` matching the event type defined in + // our step.waitForEvent call + await instance.sendEvent({type: "stripe-webhook", payload: webhookPayload}) + + return Response.json({ + status: await instance.status(), + }); + }, +}; ``` +You can call `sendEvent` multiple times, setting the value of the `type` property to match the specific `waitForEvent` calls in your Workflow. + +This allows you to wait for multiple events at once, or use `Promise.race` to wait for multiple events and allow the first event to progress the Workflow. ### InstanceStatus From eb2053256d667ce8613733f22b99d4f4bdcb59ef Mon Sep 17 00:00:00 2001 From: Matt Silverlock Date: Fri, 4 Apr 2025 14:32:06 -0400 Subject: [PATCH 09/12] changelog done --- .../workflows/2025-04-07-workflows-ga.mdx | 32 ++++++++++++++++++- .../workflows/build/events-and-parameters.mdx | 2 +- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/content/changelog/workflows/2025-04-07-workflows-ga.mdx b/src/content/changelog/workflows/2025-04-07-workflows-ga.mdx index 3db26b4aad7364..360f973e70d5b6 100644 --- a/src/content/changelog/workflows/2025-04-07-workflows-ga.mdx +++ b/src/content/changelog/workflows/2025-04-07-workflows-ga.mdx @@ -12,7 +12,7 @@ import { Render, PackageManagers, TypeScriptExample } from "~/components" [Workflows](/workflows/) is now _Generally Available_ (or "GA"): in short, it's ready for production workloads. Alongside marking Workflows as GA, we've introduced a number of changes during the beta period, including: * A new `waitForEvent` API that allows a Workflow to wait for an event to occur before continuing execution. -* Increased concurrency: you can [run up to 4,500 Workflow instances](/changelog/2025-02-25-workflows-concurrency-increased/) concurrently (and this will continue to grow) +* Increased concurrency: you can [run up to 4,500 Workflow instances](/changelog/2025-02-25-workflows-concurrency-increased/) concurrently — and this will continue to grow. * Improved observability, including new CPU time metrics that allow you to better understand which Workflow instances are consuming the most resources and/or contributing to your bill. * Support for `vitest` for testing Workflows locally and in CI/CD pipelines. @@ -31,7 +31,37 @@ For example, if you wanted to implement a human-in-the-loop approval process, yo ```ts import { Workflow, WorkflowEvent } from "cloudflare:workflows"; +export class MyWorkflow extends WorkflowEntrypoint { + async run(event: WorkflowEvent, step: WorkflowStep) { + // Other steps in your Workflow + let event = await step.waitForEvent("receive invoice paid webhook from Stripe", { type: "stripe-webhook", timeout: "1 hour" }) + // Rest of your Workflow + } +} +``` + + + +You can then send a Workflow an event from an external service via HTTP or from within a Worker using the [Workers API](/workflows/build/workers-api/) for Workflows: + + + +```ts +export default { + async fetch(req: Request, env: Env) { + const instanceId = new URL(req.url).searchParams.get("instanceId") + const webhookPayload = await req.json() + + let instance = await env.MY_WORKFLOW.get(instanceId); + // Send our event, with `type` matching the event type defined in + // our step.waitForEvent call + await instance.sendEvent({type: "stripe-webhook", payload: webhookPayload}) + return Response.json({ + status: await instance.status(), + }); + }, +}; ``` diff --git a/src/content/docs/workflows/build/events-and-parameters.mdx b/src/content/docs/workflows/build/events-and-parameters.mdx index 54e2af8ca9f393..35b5aa3c61d6c1 100644 --- a/src/content/docs/workflows/build/events-and-parameters.mdx +++ b/src/content/docs/workflows/build/events-and-parameters.mdx @@ -18,7 +18,7 @@ You can pass parameters to a Workflow in three ways: * As an optional argument to the `create` method on a [Workflow binding](/workers/wrangler/commands/#trigger) when triggering a Workflow from a Worker. * Via the `--params` flag when using the `wrangler` CLI to trigger a Workflow. -* Via the `step.waitForEvent` API, which allows a Workflow instance to wait for an event (and optional data) to be received _while it is running_. +* Via the `step.waitForEvent` API, which allows a Workflow instance to wait for an event (and optional data) to be received _while it is running_. Workflow instances can be sent events from external services over HTTP or via the Workers API for Workflows. You can pass any JSON-serializable object as a parameter. From 0132f8c25ff92aaec2dc9d5664bdde74c26d4d57 Mon Sep 17 00:00:00 2001 From: Matt Silverlock Date: Sun, 6 Apr 2025 10:29:11 -0400 Subject: [PATCH 10/12] final --- .../workflows/build/events-and-parameters.mdx | 22 ++++++++++++++++--- .../docs/workflows/build/workers-api.mdx | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/content/docs/workflows/build/events-and-parameters.mdx b/src/content/docs/workflows/build/events-and-parameters.mdx index 35b5aa3c61d6c1..ec1e3c71313215 100644 --- a/src/content/docs/workflows/build/events-and-parameters.mdx +++ b/src/content/docs/workflows/build/events-and-parameters.mdx @@ -67,7 +67,16 @@ npx wrangler@latest workflows trigger workflows-starter '{"some":"data"}' ### Wait for events -A running Workflow can wait for an event (or events) by calling `step.waitForEvent` within the Workflow. +A running Workflow can wait for an event (or events) by calling `step.waitForEvent` within the Workflow, which allows you to send events to the Workflow in one of two ways: + +1. Via the [Workers API binding](/workflows/build/workers-api/): call `instance.sendEvent` to send events to specific workflow instances. +2. Using the REST API (HTTP API)'s [Events endpoint](/api/resources/workflows/subresources/instances/subresources/events/methods/create/). + +Because `waitForEvent` is part of the `WorkflowStep` API, you can call it multiple times within a Workflow, and use control flow to conditionally wait for an event. + +Calling `waitForEvent` requires you to specify an `type`, which is used to match the corresponding `type` when sending an event to a Workflow instance. + +For example, to wait for billing webhook: @@ -83,11 +92,15 @@ export class MyWorkflow extends WorkflowEntrypoint { -TODO +The above example: + +* Calls `waitForEvent` with a `type` of `stripe-webhook` - the corresponding `sendEvent` call would thus be `await instance.sendEvent({type: "stripe-webhook", payload: webhookPayload})`. +* Uses a TypeScript [type parameter](https://www.typescriptlang.org/docs/handbook/2/generics.html) to type the return value of `step.waitForEvent` as our `IncomingStripeWebhook`. +* Continues on with the rest of the Workflow. ### Sending events to running workflows -TODO +Workflow instances that are waiting on events using the `waitForEvent` API can be sent events using the `instance.sendEvent` API: @@ -111,6 +124,9 @@ export default { +* Similar to the [`waitForEvent`](#wait-for-events) example in this guide, the `type` property our `waitForEvent` and `sendEvent` fields must match. +* To send multiple events to a Workflow that has multiple `waitForEvent` calls, call `sendEvent` with the corresponding `type` property set. +* Events can also be sent using the REST API (HTTP API)'s [Events endpoint](/api/resources/workflows/subresources/instances/subresources/events/methods/create/). ## TypeScript and type parameters diff --git a/src/content/docs/workflows/build/workers-api.mdx b/src/content/docs/workflows/build/workers-api.mdx index 6fbcc539518f75..a9e33d57ccd407 100644 --- a/src/content/docs/workflows/build/workers-api.mdx +++ b/src/content/docs/workflows/build/workers-api.mdx @@ -6,7 +6,7 @@ sidebar: --- -import { MetaInfo, Render, Type, WranglerConfig } from "~/components"; +import { MetaInfo, Render, Type, TypeScriptExample, WranglerConfig } from "~/components"; This guide details the Workflows API within Cloudflare Workers, including methods, types, and usage examples. From 60125b2d491f6fa0f41623427a92586e0900aa60 Mon Sep 17 00:00:00 2001 From: Matt Silverlock Date: Sun, 6 Apr 2025 16:23:13 -0400 Subject: [PATCH 11/12] Apply suggestions from code review Co-authored-by: Jun Lee --- src/content/docs/workflows/build/events-and-parameters.mdx | 4 ++-- src/content/docs/workflows/reference/pricing.mdx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/docs/workflows/build/events-and-parameters.mdx b/src/content/docs/workflows/build/events-and-parameters.mdx index ec1e3c71313215..0245453a5fd5f6 100644 --- a/src/content/docs/workflows/build/events-and-parameters.mdx +++ b/src/content/docs/workflows/build/events-and-parameters.mdx @@ -98,7 +98,7 @@ The above example: * Uses a TypeScript [type parameter](https://www.typescriptlang.org/docs/handbook/2/generics.html) to type the return value of `step.waitForEvent` as our `IncomingStripeWebhook`. * Continues on with the rest of the Workflow. -### Sending events to running workflows +### Send events to running workflows Workflow instances that are waiting on events using the `waitForEvent` API can be sent events using the `instance.sendEvent` API: @@ -124,7 +124,7 @@ export default { -* Similar to the [`waitForEvent`](#wait-for-events) example in this guide, the `type` property our `waitForEvent` and `sendEvent` fields must match. +* Similar to the [`waitForEvent`](#wait-for-events) example in this guide, the `type` property in our `waitForEvent` and `sendEvent` fields must match. * To send multiple events to a Workflow that has multiple `waitForEvent` calls, call `sendEvent` with the corresponding `type` property set. * Events can also be sent using the REST API (HTTP API)'s [Events endpoint](/api/resources/workflows/subresources/instances/subresources/events/methods/create/). diff --git a/src/content/docs/workflows/reference/pricing.mdx b/src/content/docs/workflows/reference/pricing.mdx index e475ddb4bb88e3..e7847df3c8b69f 100644 --- a/src/content/docs/workflows/reference/pricing.mdx +++ b/src/content/docs/workflows/reference/pricing.mdx @@ -49,7 +49,7 @@ Storage is billed using gigabyte-month (GB-month) as the billing metric, identic * Storage is calculated across all instances, and includes running, errored, sleeping and completed instances. * By default, instance state is retained for [3 days on the Free plan](/workflows/reference/limits/) and [7 days on the Paid plan](/workflows/reference/limits/). * When creating a Workflow instance, you can set a shorter state retention period if you do not need to retain state for errored or completed Workflows. -* Deleting instances via the [Workers API](/workflows/build/workers-api/), [wrangler CLI](/workers/wrangler/commands/#workflows), REST API or dashboard will free up storage. Note that it may take a few minutes for storage limits to update. +* Deleting instances via the [Workers API](/workflows/build/workers-api/), [Wrangler CLI](/workers/wrangler/commands/#workflows), REST API, or dashboard will free up storage. Note that it may take a few minutes for storage limits to update. An instance that attempts to store state when your have reached the storage limit on the Free plan will cause an error to be thrown. From ac5ab12295109d0279619b6959869d56637d6eb8 Mon Sep 17 00:00:00 2001 From: Matt Silverlock Date: Sun, 6 Apr 2025 16:24:00 -0400 Subject: [PATCH 12/12] ok --- src/content/docs/workflows/build/workers-api.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/workflows/build/workers-api.mdx b/src/content/docs/workflows/build/workers-api.mdx index a9e33d57ccd407..17654e0bcc6479 100644 --- a/src/content/docs/workflows/build/workers-api.mdx +++ b/src/content/docs/workflows/build/workers-api.mdx @@ -301,7 +301,7 @@ This is useful when you are scheduling multiple instances at once. A call to `cr * `batch` - list of Options to pass when creating an instance, including a user-provided ID and payload parameters. -Each element of the `batch` list is expected to the +Each element of the `batch` list is expected to include both `id` and `params` properties: ```ts // Create a new batch of 3 Workflow instances, each with its own ID and pass params to the Workflow instances