A local Temporal cluster running as individual Docker containers, with a Go "hello world" workflow and Wireshark for observing network traffic.
Vibe-coded with Claude Code.
Warning
This is a personal side project and may undergo breaking changes at any time without notice. If you are relying on it for anything, use a tagged release rather than tracking main.
- Docker Desktop (Mac/Windows) or Docker + Docker Compose (Linux)
docker compose up --buildThe first run downloads images and compiles the Go binaries — give it a few minutes. On subsequent runs --build can be omitted.
Startup order:
- tshark starts capturing on
temporal-net - PostgreSQL becomes healthy
temporal-setupcreates DB schema viatemporal-sql-tool, then exitstemporal-frontend,temporal-history,temporal-matching, andtemporal-internal-workerstart in parallel; each registers its IP in PostgreSQL's RingPop membership table so they can discover each othertemporal-default-namespaceretries until the frontend is ready, registers thedefaultnamespace, then exits- Temporal UI becomes available
Example workflow workers and starters are not started automatically — see Example workflows below.
docker compose run --rm hello-world-starterThis automatically starts hello-world-worker as a dependency, runs the workflow, prints the result, and exits. You should see:
✓ Workflow result: Hello, World! (from Temporal activity)
To run it again just re-run the same command. The worker stays running until you stop it:
docker compose stop hello-world-worker| URL | What it is |
|---|---|
| http://localhost:8080 | Temporal UI — browse workflows, task queues, namespaces |
| http://localhost:3000 | Wireshark — full packet capture GUI |
Packet capture is split across two containers:
- tshark runs with host networking, captures all traffic on the
temporal-netbridge, and writes a rolling ring-buffer of pcap files (5 × 50 MB) to./captures/ - wireshark provides the web GUI at http://localhost:3000 and mounts
./capturesread-only
To open a capture:
- Open http://localhost:3000 in your browser
- In the Wireshark GUI, go to File → Open and navigate to
/captures/ - Open the latest
temporal_*.pcapfile - Enable View → Name Resolution → Resolve Network Addresses to see container names instead of IPs
| Filter | What it shows |
|---|---|
tcp.port == 7233 |
All Temporal gRPC traffic (client ↔ frontend) |
ip.src_host != "wireshark" && ip.dst_host != "wireshark" && !pgsql |
Everything except Wireshark's own traffic and PostgreSQL chatter — good starting point |
tcp.port == 7233 && ip.src_host != "wireshark" && ip.dst_host != "wireshark" |
Only Temporal gRPC, no Wireshark noise |
(ip.src_host == "hello-world-worker" || ip.dst_host == "hello-world-worker") |
All traffic to/from the worker |
(ip.src_host == "hello-world-starter" || ip.dst_host == "hello-world-starter") |
All traffic to/from the starter (workflow submission) |
ip.src_host == "temporal-frontend" || ip.dst_host == "temporal-frontend" |
All traffic in and out of the frontend service |
ip.src_host == "temporal-history" || ip.dst_host == "temporal-history" |
All traffic in and out of the history service |
ip.src_host == "temporal-matching" || ip.dst_host == "temporal-matching" |
All traffic in and out of the matching service |
(ip.addr == 172.20.0.21 || ip.addr == 172.20.0.22 || ip.addr == 172.20.0.23 || ip.addr == 172.20.0.24) && !pgsql |
Inter-service gRPC traffic only (excludes DB) |
tcp.port == 5432 |
PostgreSQL only — useful for watching schema/persistence activity |
tcp.port == 8080 |
Temporal UI HTTP traffic |
docs/README.md — a native desktop GUI and headless CLI that produces interactive Mermaid diagrams, a statistics report, and a SQL query engine over the packet data.
cd tools/temporal-lens
go build -tags nogui -o temporal-lens .
./temporal-lens captures/temporal_00001.pcap # all traffic
./temporal-lens captures/temporal_00001.pcap --only grpc # gRPC only
./temporal-lens captures/temporal_00001.pcap --json --quiet | jq '.grpc_calls | map(.method) | unique'See docs/README.md for installation, build instructions, and all flags.
Five additional workflows demonstrate different Temporal features. Nothing starts automatically — every worker and starter requires an explicit command. Running a starter automatically brings up its worker as a dependency, so you only need one command per workflow.
docker compose run --rm scheduled-starterCreates a schedule that triggers ScheduledReportWorkflow every 30 seconds. Watch repeated runs appear in the Temporal UI under Schedules.
# 1. Start a workflow that blocks waiting for a signal
docker compose run --rm signals-starter
# 2a. Approve it (runs ProcessOrderActivity)
docker compose run --rm signals-approve
# 2b. Or reject it (runs CancelOrderActivity)
docker compose run --rm signals-rejectThe workflow exposes a status query you can inspect in the Temporal UI while it is pending.
docker compose run --rm child-workflows-starterDataPipelineWorkflow spawns five child workflows in parallel, one per item. Observe the parent-child coordination traffic in Wireshark.
docker compose run --rm retries-starterUnreliableActivity deliberately fails on attempts 1 and 2, then succeeds on attempt 3. The retry policy uses exponential backoff (2 s → 4 s → success). Watch RespondActivityTaskFailed RPCs in Wireshark followed by a final RespondActivityTaskCompleted.
# Happy path: flight + hotel + car all succeed
docker compose run --rm saga-starter
# Failure path: hotel booking fails → flight is automatically cancelled
docker compose run --rm saga-fail-starterBookingWorkflow books three resources in sequence, registering a compensation action after each. If any step fails, completed bookings are rolled back in reverse order.
docker compose downAll data is ephemeral — PostgreSQL uses a tmpfs mount and is wiped on shutdown.
docker-compose.yml # All containers
temporal-config/
dynamicconfig/ # Temporal server runtime config (dynamic config)
scripts/setup.sh # DB schema init script (run by temporal-setup container)
examples/
hello-world/ # Simple hello-world workflow
scheduled/ # Temporal Schedules (periodic trigger)
signals/ # Signals + queries (approval workflow)
child-workflows/ # Parallel child workflow fan-out
retries/ # Activity retries with exponential backoff
saga/ # Saga pattern with compensation
Each example follows the same layout:
workflow/workflow.go # Workflow + Activity definitions
worker/ # Worker (manual: docker compose run --rm)
starter/ # Starter (manual: docker compose run --rm)
tshark/Dockerfile # Minimal tshark capture image
captures/ # Rolling pcap files written by tshark
reports/ # Generated reports (gitignored)
wireshark/hosts # Static IP → container name mappings
docs/
README.md # temporal-lens tool — installation and quick reference
user-guide.md # Full end-user documentation
tools/
temporal-lens/ # Capture analysis tool (GUI + CLI)