|
| 1 | +--- |
| 2 | +title: Astro |
| 3 | +--- |
| 4 | + |
| 5 | +This guide will walk through setting up your first workflow in an Astro app. Along the way, you'll learn more about the concepts that are fundamental to using the development kit in your own projects. |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +<Steps> |
| 10 | + |
| 11 | +<Step> |
| 12 | +## Create Your Astro Project |
| 13 | + |
| 14 | +Start by creating a new Astro project. This command will create a new directory named `my-workflow-app` and setup a minimal Astro project inside it. |
| 15 | + |
| 16 | +```bash |
| 17 | +npm create astro@latest my-workflow-app -- --template minimal --install --yes |
| 18 | +``` |
| 19 | + |
| 20 | +Enter the newly made directory: |
| 21 | + |
| 22 | +```bash |
| 23 | +cd my-workflow-app |
| 24 | +``` |
| 25 | + |
| 26 | +### Install `workflow` |
| 27 | + |
| 28 | +```package-install |
| 29 | +npm i workflow |
| 30 | +``` |
| 31 | + |
| 32 | +### Configure Astro |
| 33 | + |
| 34 | +Add `workflow()` to your Astro config. This enables usage of the `"use workflow"` and `"use step"` directives. |
| 35 | + |
| 36 | +```typescript title="astro.config.mjs" lineNumbers |
| 37 | +// @ts-check |
| 38 | +import { defineConfig } from "astro/config"; |
| 39 | +import { workflow } from "workflow/astro"; |
| 40 | + |
| 41 | +// https://astro.build/config |
| 42 | +export default defineConfig({ |
| 43 | + integrations: [workflow()], |
| 44 | +}); |
| 45 | +``` |
| 46 | + |
| 47 | +<Accordion type="single" collapsible> |
| 48 | + <AccordionItem value="typescript-intellisense" className="[&_h3]:my-0"> |
| 49 | + <AccordionTrigger className="text-sm"> |
| 50 | + ### Setup IntelliSense for TypeScript (Optional) |
| 51 | + </AccordionTrigger> |
| 52 | + <AccordionContent className="[&_p]:my-2"> |
| 53 | + |
| 54 | +To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json`: |
| 55 | + |
| 56 | +```json title="tsconfig.json" lineNumbers |
| 57 | +{ |
| 58 | + "compilerOptions": { |
| 59 | + // ... rest of your TypeScript config |
| 60 | + "plugins": [ |
| 61 | + { |
| 62 | + "name": "workflow" // [!code highlight] |
| 63 | + } |
| 64 | + ] |
| 65 | + } |
| 66 | +} |
| 67 | +``` |
| 68 | + |
| 69 | + </AccordionContent> |
| 70 | + </AccordionItem> |
| 71 | +</Accordion> |
| 72 | + |
| 73 | +</Step> |
| 74 | + |
| 75 | +<Step> |
| 76 | + |
| 77 | +## Create Your First Workflow |
| 78 | + |
| 79 | +Create a new file for our first workflow: |
| 80 | + |
| 81 | +```typescript title="src/workflows/user-signup.ts" lineNumbers |
| 82 | +import { sleep } from "workflow"; |
| 83 | + |
| 84 | +export async function handleUserSignup(email: string) { |
| 85 | + "use workflow"; // [!code highlight] |
| 86 | + |
| 87 | + const user = await createUser(email); |
| 88 | + await sendWelcomeEmail(user); |
| 89 | + |
| 90 | + await sleep("5s"); // Pause for 5s - doesn't consume any resources |
| 91 | + await sendOnboardingEmail(user); |
| 92 | + |
| 93 | + return { userId: user.id, status: "onboarded" }; |
| 94 | +} |
| 95 | + |
| 96 | +``` |
| 97 | + |
| 98 | +We'll fill in those functions next, but let's take a look at this code: |
| 99 | + |
| 100 | +* We define a **workflow** function with the directive `"use workflow"`. Think of the workflow function as the _orchestrator_ of individual **steps**. |
| 101 | +* The Workflow DevKit's `sleep` function allows us to suspend execution of the workflow without using up any resources. A sleep can be a few seconds, hours, days, or even months long. |
| 102 | + |
| 103 | +## Create Your Workflow Steps |
| 104 | + |
| 105 | +Let's now define those missing functions. |
| 106 | + |
| 107 | +```typescript title="src/workflows/user-signup.ts" lineNumbers |
| 108 | +import { FatalError } from "workflow" |
| 109 | + |
| 110 | +// Our workflow function defined earlier |
| 111 | + |
| 112 | +async function createUser(email: string) { |
| 113 | + "use step"; // [!code highlight] |
| 114 | + |
| 115 | + console.log(`Creating user with email: ${email}`); |
| 116 | + |
| 117 | + // Full Node.js access - database calls, APIs, etc. |
| 118 | + return { id: crypto.randomUUID(), email }; |
| 119 | +} |
| 120 | + |
| 121 | +async function sendWelcomeEmail(user: { id: string; email: string; }) { |
| 122 | + "use step"; // [!code highlight] |
| 123 | + |
| 124 | + console.log(`Sending welcome email to user: ${user.id}`); |
| 125 | + |
| 126 | + if (Math.random() < 0.3) { |
| 127 | + // By default, steps will be retried for unhandled errors |
| 128 | + throw new Error("Retryable!"); |
| 129 | + } |
| 130 | +} |
| 131 | + |
| 132 | +async function sendOnboardingEmail(user: { id: string; email: string}) { |
| 133 | + "use step"; // [!code highlight] |
| 134 | + |
| 135 | + if (!user.email.includes("@")) { |
| 136 | + // To skip retrying, throw a FatalError instead |
| 137 | + throw new FatalError("Invalid Email"); |
| 138 | + } |
| 139 | + |
| 140 | + console.log(`Sending onboarding email to user: ${user.id}`); |
| 141 | +} |
| 142 | +``` |
| 143 | + |
| 144 | +Taking a look at this code: |
| 145 | + |
| 146 | +* Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`. |
| 147 | +* If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count). |
| 148 | +* Steps can throw a `FatalError` if an error is intentional and should not be retried. |
| 149 | + |
| 150 | +<Callout> |
| 151 | +We'll dive deeper into workflows, steps, and other ways to suspend or handle events in [Foundations](/docs/foundations). |
| 152 | +</Callout> |
| 153 | + |
| 154 | +</Step> |
| 155 | + |
| 156 | +<Step> |
| 157 | + |
| 158 | +## Create Your Route Handler |
| 159 | + |
| 160 | +To invoke your new workflow, we'll have to add your workflow to a `POST` API route handler, `src/pages/api/signup.ts` with the following code: |
| 161 | + |
| 162 | +```typescript title="src/pages/api/signup.ts" |
| 163 | +import type { APIRoute } from "astro"; |
| 164 | +import { start } from "workflow/api"; |
| 165 | +import { handleUserSignup } from "../../workflows/user-signup"; |
| 166 | + |
| 167 | +export const POST: APIRoute = async ({ request }: { request: Request }) => { |
| 168 | + const { email } = await request.json(); |
| 169 | + |
| 170 | + // Executes asynchronously and doesn't block your app |
| 171 | + await start(handleUserSignup, [email]); |
| 172 | + return Response.json({ |
| 173 | + message: "User signup workflow started", |
| 174 | + }); |
| 175 | +}; |
| 176 | + |
| 177 | +export const prerender = false; // Don't prerender this page since it's an API route |
| 178 | +``` |
| 179 | + |
| 180 | +This route handler creates a `POST` request endpoint at `/api/signup` that will trigger your workflow. |
| 181 | + |
| 182 | +<Callout> |
| 183 | +Workflows can be triggered from API routes or any server-side code. |
| 184 | +</Callout> |
| 185 | + |
| 186 | +</Step> |
| 187 | + |
| 188 | +</Steps> |
| 189 | + |
| 190 | +## Run in Development |
| 191 | + |
| 192 | +To start your development server, run the following command in your terminal in the Vite root directory: |
| 193 | + |
| 194 | +```bash |
| 195 | +npm run dev |
| 196 | +``` |
| 197 | + |
| 198 | +Once your development server is running, you can trigger your workflow by running this command in the terminal: |
| 199 | + |
| 200 | +```bash |
| 201 | +curl -X POST --json '{"email":"[email protected]"}' http://localhost:5173/api/signup |
| 202 | +``` |
| 203 | + |
| 204 | +Check the Astro development server logs to see your workflow execute as well as the steps that are being processed. |
| 205 | + |
| 206 | +Additionally, you can use the [Workflow DevKit CLI or Web UI](/docs/observability) to inspect your workflow runs and steps in detail. |
| 207 | + |
| 208 | +```bash |
| 209 | +npx workflow inspect runs |
| 210 | +# or add '--web' for an interactive Web based UI |
| 211 | +``` |
| 212 | + |
| 213 | +<img src="/o11y-ui.png" alt="Workflow DevKit Web UI" /> |
| 214 | + |
| 215 | +--- |
| 216 | + |
| 217 | +## Deploying to Production |
| 218 | + |
| 219 | +Workflow DevKit apps currently work best when deployed to [Vercel](https://vercel.com/home) and needs no special configuration. |
| 220 | + |
| 221 | +To deploy your Astro project to Vercel, ensure that the [Astro Vercel adapter](https://docs.astro.build/en/guides/integrations-guide/vercel) is configured: |
| 222 | + |
| 223 | +```bash |
| 224 | +npx astro add vercel |
| 225 | +``` |
| 226 | + |
| 227 | +Additionally, check the [Deploying](/docs/deploying) section to learn how your workflows can be deployed elsewhere. |
| 228 | + |
| 229 | +## Next Steps |
| 230 | + |
| 231 | +* Learn more about the [Foundations](/docs/foundations). |
| 232 | +* Check [Errors](/docs/errors) if you encounter issues. |
| 233 | +* Explore the [API Reference](/docs/api-reference). |
0 commit comments