Client -> FastAPI -> S2 jobs stream -> Worker -> LangGraph + OpenAI
Client <- FastAPI SSE <- S2 run events stream <- Worker
FastAPI enqueues work in S2. A worker claims the run with an S2 lease, runs LangGraph, streams OpenAI tokens into S2, and clients resume with after=<last_s2_seq>.
cd /Users/infiniteregrets/Documents/s2-oss/s2-langgraph-fastapi-s2-demo
python -m venv .venv
. .venv/bin/activate
pip install -e ../../s2-sdk-python -e .S2 Lite:
cd /Users/infiniteregrets/Documents/s2-oss/s2
just lite --port 8080Postgres:
docker run --rm --name langgraph-postgres \
-e POSTGRES_PASSWORD=postgres \
-e POSTGRES_DB=langgraph \
-p 5432:5432 \
postgres:16Common env for the API and worker terminals:
cd /Users/infiniteregrets/Documents/s2-oss/s2-langgraph-fastapi-s2-demo
. .venv/bin/activate
export S2_ACCOUNT_ENDPOINT="http://localhost:8080"
export S2_BASIN_ENDPOINT="http://localhost:8080"
export S2_ACCESS_TOKEN="ignored"
export S2_BASIN="agent-demo"
export S2_BOOTSTRAP_BASIN="true"
export S2_STREAM_PREFIX="langgraph-demo"
export LANGGRAPH_POSTGRES_URL="postgresql://postgres:postgres@localhost:5432/langgraph?sslmode=disable"
export WORKER_LEASE_SECONDS="10"
export WORKER_HEARTBEAT_SECONDS="2"
export WORKER_POLL_SECONDS="1"
export OPENAI_API_KEY="sk-..."
export OPENAI_MODEL="gpt-4.1-mini"API:
uvicorn app:app --host 127.0.0.1 --port 8000Worker:
python worker.pyCreate a run:
curl -sS -X POST http://127.0.0.1:8000/threads \
-H 'content-type: application/json' \
-d '{"prompt":"Find the biggest revenue delta in the workbook"}'Stream it:
curl -N "http://127.0.0.1:8000/runs/<run_id>/events?after=-1"Resume after the last SSE id:
curl -N "http://127.0.0.1:8000/runs/<run_id>/events?after=<last_id>"Re-enqueue a run:
curl -sS -X POST "http://127.0.0.1:8000/runs/<run_id>/resume"