andRace
Run multiple steps in parallel and use the first one that finishes. Perfect for timeouts, fallbacks, or getting the fastest response.
Quick Start​
Get data from whichever source responds first:
import { createWorkflowChain, andThen, andRace } from "@voltagent/core";
import { z } from "zod";
const workflow = createWorkflowChain({
id: "get-user-data",
input: z.object({ userId: z.string() }),
}).andRace([
// Fast: Check cache (100ms)
andThen({
id: "check-cache",
execute: async ({ data }) => {
const cached = await checkCache(data.userId);
if (cached) return { data: cached, source: "cache" };
throw new Error("Not in cache");
},
}),
// Medium: Database (300ms)
andThen({
id: "check-database",
execute: async ({ data }) => {
const user = await database.getUser(data.userId);
return { data: user, source: "database" };
},
}),
// Slow: External API (1000ms)
andThen({
id: "fetch-from-api",
execute: async ({ data }) => {
const response = await fetch(`/api/users/${data.userId}`);
return { data: await response.json(), source: "api" };
},
}),
]);
const result = await workflow.run({ userId: "123" });
// If cache has data: returns in ~100ms from cache
// If cache misses: returns in ~300ms from database
// If both fail: returns in ~1000ms from API
How It Works​
- All steps start at the same time
- First one to finish "wins"
- Its result becomes the workflow result
- Other steps stop running
- If winner fails, next fastest wins
Think of it like a race - whoever crosses the finish line first wins, regardless of who started strongest.
Function Signature​
.andRace([step1, step2, step3]) // Array of steps to race
Common Patterns​
Timeout Pattern​
Add a timeout to any operation:
.andRace([
// Main operation
andThen({
id: "slow-api",
execute: async ({ data }) => {
const result = await slowAPICall(data);
return { result, timedOut: false };
}
}),
// Timeout after 5 seconds
andThen({
id: "timeout",
execute: async () => {
await new Promise(resolve => setTimeout(resolve, 5000));
return { result: "Timeout", timedOut: true };
}
})
])
Multiple AI Providers​
Get response from fastest AI:
.andRace([
andAgent(
({ data }) => data.prompt,
openaiAgent,
{ schema: z.object({ response: z.string(), ai: z.literal("openai") }) }
),
andAgent(
({ data }) => data.prompt,
claudeAgent,
{ schema: z.object({ response: z.string(), ai: z.literal("claude") }) }
),
andAgent(
({ data }) => data.prompt,
geminiAgent,
{ schema: z.object({ response: z.string(), ai: z.literal("gemini") }) }
)
])
Cache vs Database​
Try cache first, fall back to database:
.andRace([
// Try cache (fast)
andThen({
id: "cache-lookup",
execute: async ({ data }) => {
const cached = await cache.get(data.key);
if (!cached) throw new Error("Cache miss");
return { value: cached, from: "cache" };
}
}),
// Fall back to database (slower)
andThen({
id: "db-lookup",
execute: async ({ data }) => {
const value = await db.find(data.key);
await cache.set(data.key, value); // Update cache
return { value, from: "database" };
}
})
])
Error Handling​
If the fastest step fails, the race continues:
.andRace([
andThen({
id: "unreliable-fast",
execute: async () => {
if (Math.random() > 0.5) {
throw new Error("Failed!");
}
return { result: "fast" };
}
}),
andThen({
id: "reliable-slow",
execute: async () => {
await sleep(1000);
return { result: "slow but reliable" };
}
})
])
// If fast fails, you get slow result
// If fast succeeds, you get fast result
Performance Comparison​
// Without race: Always slow (2 seconds)
.andThen({ execute: async () => await slowAPI() })
// With race: Usually fast (50ms)
.andRace([
andThen({ execute: async () => await cache() }), // 50ms
andThen({ execute: async () => await database() }), // 500ms
andThen({ execute: async () => await slowAPI() }) // 2000ms
])
Best Practices​
1. Order by Speed​
// Good: Fastest first
.andRace([
cacheStep, // 10ms
databaseStep, // 100ms
apiStep // 1000ms
])
2. Handle Different Results​
.andRace([...steps])
.andThen({
execute: async ({ data }) => {
// Check which source won
if (data.source === "cache") {
console.log("Got cached data");
}
return data;
}
})
3. Use for Redundancy​
// Multiple APIs for reliability
.andRace([
primaryAPI,
backupAPI,
fallbackAPI
])
Comparison with andAll​
| Feature | andRace | andAll |
|---|---|---|
| Returns | First to finish | All results |
| Speed | Fast as possible | Slow as slowest |
| Use case | Need any result | Need all results |
| Failure | Continues if one fails | Fails if any fail |