You are starting from a real workshop app: enter a ticker, run four web searches, then stream a memo. In the baseline version, one intermittent search error can stop the full run. By the end, you keep the same UI and flow, but runs finish far more often.
This tutorial stays in one repo the whole time: fork ojusave/workshop-demo, deploy it, edit a small set of files, then add one more Render service near the end.
Important note
This app and tutorial are for education and demos only. Output is not investment advice, and it should not be used for real financial decisions.
The presenter, conference, and company are not responsible for actions taken from generated output.
Golden path
Use a single repository throughout.
| Phase | Steps | What you do |
|---|---|---|
| Deploy baseline | 02 | Fork, Blueprint deploy, ANTHROPIC_API_KEY + EXA_API_KEY, confirm the baseline run in the UI |
| See the problem | 03–04 | Trace one run; understand why Promise.all + maybeFail kills most batches |
| Add reliable task runs | 05–08 | Edit 5 files: SDK, task(), index.ts, dispatch from research.ts |
| Wire Render services | 09–10 | Redeploy web, then create the task service and copy its slug env var |
| Confirm | 11 | Same ticker, far more runs complete |
Files you edit (everything else stays untouched):
tasks/package.jsontasks/src/search.tstasks/src/index.ts(new)tasks/src/research.tsserver/package.json
Files to understand before editing:
server/src/runner.ts: starts one research run and streams progress events to the browser.tasks/src/research.ts: orchestrates fan-out search work and fan-in synthesis.tasks/src/search.ts: runs each Exa query and includes themaybeFailtransient error simulation.tasks/src/synthesize.ts: builds the final memo from collected sources.
Why this helps
The baseline app fails often by design: each search has about a 30% chance to throw a fake rate-limit error, and all four searches run in one Promise.all.
That means full-run success is about 0.7^4 ≈ 24%.
The goal is simple: keep the UI and business logic, but isolate each search run and add retries so one transient dependency error does not fail the full user request as often.
What you’ll learn
- Why parallel work in one process fails in batches.
- How to register a task with retry policy.
- How the web service dispatches task runs and waits for completion.
- How to add the second Render service when you are ready.
- How to verify the before/after reliability difference.
What you’ll need
- A GitHub account.
- A Render account. Starter plan is enough.
- Node.js 20+ if you run the sample app locally.
- Basic Git and TypeScript. No prior task-run experience.
Final architecture
flowchart LR browser(["Browser"]) web["Web service<br/>waits + memo"] tasksvc["Task service<br/>one run per search"] exa(["Exa"]) claude(["Anthropic"]) browser --> web web -->|4 runs| tasksvc tasksvc --> exa web --> claude
The service name and exact Render setup show up when we reach that step. For now, focus on the baseline behavior and the small code diff.
On this page
- One fork from workshop-demo: deploy baseline, edit five files, then add one more Render service
- The baseline fails often because four searches run in one Promise.all with simulated transient errors
- You keep the same app shape and upgrade reliability in place