diff --git a/docs/app/(home)/components/frameworks.tsx b/docs/app/(home)/components/frameworks.tsx index 1d21d9755..041871417 100644 --- a/docs/app/(home)/components/frameworks.tsx +++ b/docs/app/(home)/components/frameworks.tsx @@ -1,12 +1,12 @@ -"use client"; +'use client'; -import { track } from "@vercel/analytics"; -import Link from "next/link"; -import type { ComponentProps } from "react"; -import { toast } from "sonner"; -import { Badge } from "@/components/ui/badge"; +import { track } from '@vercel/analytics'; +import Link from 'next/link'; +import type { ComponentProps } from 'react'; +import { toast } from 'sonner'; +import { Badge } from '@/components/ui/badge'; -export const Express = (props: ComponentProps<"svg">) => ( +export const Express = (props: ComponentProps<'svg'>) => ( ) => ( ); -export const AstroDark = (props: ComponentProps<"svg">) => ( +export const AstroDark = (props: ComponentProps<'svg'>) => ( ) => ( ); -export const AstroLight = (props: ComponentProps<"svg">) => ( +export const AstroLight = (props: ComponentProps<'svg'>) => ( ) => ( ); -export const AstroGray = (props: ComponentProps<"svg">) => ( +export const AstroGray = (props: ComponentProps<'svg'>) => ( ) => ( ); -export const TanStack = (props: ComponentProps<"svg">) => ( +export const TanStack = (props: ComponentProps<'svg'>) => ( ) => ( ); -export const TanStackGray = (props: ComponentProps<"svg">) => ( +export const TanStackGray = (props: ComponentProps<'svg'>) => ( ) => ( ); -export const Vite = (props: ComponentProps<"svg">) => ( +export const Vite = (props: ComponentProps<'svg'>) => ( ) => ( ); -export const Nitro = (props: ComponentProps<"svg">) => ( +export const Nitro = (props: ComponentProps<'svg'>) => ( ) => ( /> ) => ( ); -export const SvelteKit = (props: ComponentProps<"svg">) => ( +export const SvelteKit = (props: ComponentProps<'svg'>) => ( ) => ( ); -export const SvelteKitGray = (props: ComponentProps<"svg">) => ( +export const SvelteKitGray = (props: ComponentProps<'svg'>) => ( ) => ( ); -export const Nuxt = (props: ComponentProps<"svg">) => ( +export const Nuxt = (props: ComponentProps<'svg'>) => ( ) => ( ); -export const NuxtGray = (props: ComponentProps<"svg">) => ( +export const NuxtGray = (props: ComponentProps<'svg'>) => ( ) => ( ); -export const Hono = (props: ComponentProps<"svg">) => ( +export const Hono = (props: ComponentProps<'svg'>) => ( Hono ) => ( ); -export const HonoGray = (props: ComponentProps<"svg">) => ( +export const HonoGray = (props: ComponentProps<'svg'>) => ( Hono ) => ( ); -export const Bun = (props: ComponentProps<"svg">) => ( +export const Bun = (props: ComponentProps<'svg'>) => ( ) => ( id="Top" d="M35.12,5.53A16.41,16.41,0,0,1,29.49,18c-.28.25-.06.73.3.59,3.37-1.31,7.92-5.23,6-13.14C35.71,5,35.12,5.12,35.12,5.53Zm2.27,0A16.24,16.24,0,0,1,39,19c-.12.35.31.65.55.36C41.74,16.56,43.65,11,37.93,5,37.64,4.74,37.19,5.14,37.39,5.49Zm2.76-.17A16.42,16.42,0,0,1,47,17.12a.33.33,0,0,0,.65.11c.92-3.49.4-9.44-7.17-12.53C40.08,4.54,39.82,5.08,40.15,5.32ZM21.69,15.76a16.94,16.94,0,0,0,10.47-9c.18-.36.75-.22.66.18-1.73,8-7.52,9.67-11.12,9.45C21.32,16.4,21.33,15.87,21.69,15.76Z" fill="#ccbea7" - style={{ fillRule: "evenodd" }} + style={{ fillRule: 'evenodd' }} /> ) => ( ); -export const BunGray = (props: ComponentProps<"svg">) => ( +export const BunGray = (props: ComponentProps<'svg'>) => ( ) => ( id="Top" d="M35.12,5.53A16.41,16.41,0,0,1,29.49,18c-.28.25-.06.73.3.59,3.37-1.31,7.92-5.23,6-13.14C35.71,5,35.12,5.12,35.12,5.53Zm2.27,0A16.24,16.24,0,0,1,39,19c-.12.35.31.65.55.36C41.74,16.56,43.65,11,37.93,5,37.64,4.74,37.19,5.14,37.39,5.49Zm2.76-.17A16.42,16.42,0,0,1,47,17.12a.33.33,0,0,0,.65.11c.92-3.49.4-9.44-7.17-12.53C40.08,4.54,39.82,5.08,40.15,5.32ZM21.69,15.76a16.94,16.94,0,0,0,10.47-9c.18-.36.75-.22.66.18-1.73,8-7.52,9.67-11.12,9.45C21.32,16.4,21.33,15.87,21.69,15.76Z" fill="var(--color-background)" - style={{ fillRule: "evenodd" }} + style={{ fillRule: 'evenodd' }} /> ) => ( ); -export const Nest = (props: ComponentProps<"svg">) => ( +export const Nest = (props: ComponentProps<'svg'>) => ( ) => ( ); -export const NestGray = (props: ComponentProps<"svg">) => ( +export const NestGray = (props: ComponentProps<'svg'>) => ( ) => ( ); -export const Next = (props: ComponentProps<"svg">) => ( +export const Next = (props: ComponentProps<'svg'>) => ( Next.js @@ -681,8 +681,8 @@ export const Next = (props: ComponentProps<"svg">) => ( export const Frameworks = () => { const handleRequest = (framework: string) => { - track("Framework requested", { framework: framework.toLowerCase() }); - toast.success("Request received", { + track('Framework requested', { framework: framework.toLowerCase() }); + toast.success('Request received', { description: `Thanks for expressing interest in ${framework}. We will be adding support for it soon.`, }); }; @@ -742,21 +742,21 @@ export const Frameworks = () => {
handleRequest("NestJS")} + onClick={() => handleRequest('NestJS')} >
handleRequest("TanStack")} + onClick={() => handleRequest('TanStack')} >
handleRequest("Astro")} + onClick={() => handleRequest('Astro')} > diff --git a/packages/core/e2e/e2e.test.ts b/packages/core/e2e/e2e.test.ts index 92336b08e..a1a701d61 100644 --- a/packages/core/e2e/e2e.test.ts +++ b/packages/core/e2e/e2e.test.ts @@ -776,4 +776,27 @@ describe('e2e', () => { expect(returnValue).toBe('Result: 21'); } ); + + test( + 'stepExhaustsRetriesWorkflow - workflow fails when step exhausts max retries', + { timeout: 120_000 }, + async () => { + // This workflow has a step that always throws a regular error. + // After exhausting max retries (default 3), the error should bubble up + // to the workflow function. Since the workflow doesn't handle it, + // the workflow run should enter a failed state. + const run = await triggerWorkflow('stepExhaustsRetriesWorkflow', []); + const returnValue = await getWorkflowReturnValue(run.runId); + + // The workflow should fail with WorkflowRunFailedError + expect(returnValue).toHaveProperty('name'); + expect(returnValue.name).toBe('WorkflowRunFailedError'); + + // Verify the run is in failed status + const { json: runData } = await cliInspectJson(`runs ${run.runId}`); + expect(runData.status).toBe('failed'); + expect(runData.error).toBeDefined(); + expect(runData.error.message).toContain('failed after max retries'); + } + ); }); diff --git a/workbench/example/workflows/99_e2e.ts b/workbench/example/workflows/99_e2e.ts index df5e0b22c..3b2f5e208 100644 --- a/workbench/example/workflows/99_e2e.ts +++ b/workbench/example/workflows/99_e2e.ts @@ -559,3 +559,21 @@ export async function closureVariableWorkflow(baseValue: number) { const output = await calculate(); return output; } + +////////////////////////////////////////////////////////// + +// Step that always throws a regular error (not FatalError) +// This will exhaust max retries and the error should bubble up to the workflow +async function stepThatAlwaysFailsWithRegularError() { + 'use step'; + throw new Error('This step always fails with a regular error'); +} + +// Workflow that calls a step that always fails +// The step will exhaust max retries and the error should bubble up, +// causing the workflow run to enter a failed state +export async function stepExhaustsRetriesWorkflow() { + 'use workflow'; + await stepThatAlwaysFailsWithRegularError(); + return 'never reached'; +}