The Render Workflow service for SF Pulse Python is created manually in the Dashboard because Render Workflows are not yet first-class in render.yaml.
-
Render Dashboard → New → Workflow.
-
Connect your GitHub fork of
render-examples/sf-pulse-python. Branch:main. -
Name:
sf-pulse-python-workflow -
Build Command:
pip install --upgrade uv && uv sync --frozen -
Start Command:
uv run python -m workflow.main -
Plan: Starter
-
Under Environment, attach the
sf-pulse-python-envenv group plus:Variable Source DATABASE_URLCopy from sf-pulse-python-dbconnection stringWorkflow services don't currently support
fromDatabase/fromServicereferences in the YAML the same way web services do, so setDATABASE_URLdirectly here once. -
Save and deploy.
After the worker is live, go to the service's Settings page. Copy the Slug value. You'll set it on the cron service as SF_PULSE_WORKFLOW_SLUG.
On the sf-pulse-python-daily cron service (provisioned by render.yaml):
| Variable | Value |
|---|---|
RENDER_API_KEY |
Dashboard → Account Settings → API Keys → New API Key |
SF_PULSE_WORKFLOW_SLUG |
Slug from step 2 |
The cron entrypoint (bin/trigger_workflow.py) reads these env vars and calls:
client = Render()
run = client.workflows.run_task(f"{slug}/daily-refresh", [])There are two supported flows.
The fastest way to populate a local database. Bypasses the Render Workflows SDK entirely and calls the source scrapers + apply_discovered_items in-process:
uv run python -c "import asyncio; from app.refresh import run_daily_refresh; asyncio.run(run_daily_refresh())"This is the recommended path for local development and for the smoke tests in tests/test_refresh.py.
Note: calling
daily_refresh()fromworkflow.tasks.daily_refreshdirectly does not work — it's wrapped by@app.taskand requires the workflow runtime'scurrent_clientContextVar.
To exercise the SDK boundary (task registration, retry, subtask fan-out), run the worker under the Render CLI:
render workflows dev -- python -m workflow.mainThen in another terminal, trigger the task manually:
from render_sdk import Render
r = Render()
r.workflows.run_task("sf-pulse-python-workflow/daily-refresh", [])RENDER_API_KEYnot configured in the cron logs → set it on the cron service env vars.Task not found→ double-check the workflow slug and that the worker has deployed at least once.- Tasks timeout → the orchestrator has a 600s timeout. If sources are slow, increase the timeout on the
daily_refreshdecorator. - No restaurants/events appear after a run → check that
LLM_API_KEYis set on the workflow service. Without it, only the regex sources (SFist, Michelin, FunCheap, FAMSF, Cal Academy) produce results.