Course
ai-dev-tools-zoomcamp
Question
In Homework 3 (module 03) the assignment tells you to run your CI workflow
locally with act. My workflow starts a postgres:16 service container
with a pg_isready healthcheck, and act prints container health … is healthy. But when the job boots the Agent Relay API with
RELAY_DATABASE_URL=postgresql+psycopg://relay:relay@localhost:5432/relay,
it crashes:
text
psycopg.OperationalError: connection failed: connection to server at
"127.0.0.1", port 5432 failed: Connection refused
The identical workflow passes on GitHub Actions. Why does localhost work
there but not under act, and what hostname should I use?
Answer
Because GitHub and act place service containers in different networks:
GitHub Actions publishes service ports on the job runner's loopback, so
localhost:5432 is correct there.
act runs each service as a separate container on a user-defined docker
network shared with the job container. Nothing is published on the job's
loopback; the service is reachable by its service name (the key under
services:), resolved by docker's embedded DNS. Under act the host is
postgres, not localhost. The giveaway is the error text itself: it
retries ::1 and 127.0.0.1 — loopback — while the healthy service sits
one hop away on the act network.
Fix that is correct in BOTH worlds — parameterise the host with a per-runner
default (vars is legal in step env and, unlike env, in job-level if):
YAML
jobs:
test:
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: relay
POSTGRES_PASSWORD: relay
POSTGRES_DB: relay
options: >-
--health-cmd "pg_isready -U relay -d relay"
--health-interval 3s --health-timeout 3s --health-retries 10
steps:
- name: boot api against postgres
env:
RELAY_DATABASE_URL: >-
postgresql+psycopg://relay:relay@${{ vars.DB_HOST || 'localhost' }}:5432/relay
run: |
uv run uvicorn main:app --port 8005 &
...
Locally: act … --var DB_HOST=postgres. On GitHub vars.DB_HOST is unset, the
expression falls back to localhost, and the workflow is unchanged.
Sanity checks: docker network inspect <act-…-test-network> lists both
containers; getent hosts postgres resolves inside the job container; and a
service that is healthy in act's log yet "refused" from the job is always
this networking difference, never a bad healthcheck.
Checklist
Course
ai-dev-tools-zoomcamp
Question
In Homework 3 (module 03) the assignment tells you to run your CI workflow
locally with act. My workflow starts a postgres:16 service container
with a pg_isready healthcheck, and act prints container health … is healthy. But when the job boots the Agent Relay API with
RELAY_DATABASE_URL=postgresql+psycopg://relay:relay@localhost:5432/relay,
it crashes:
text
Answer
Because GitHub and act place service containers in different networks:
GitHub Actions publishes service ports on the job runner's loopback, so
localhost:5432 is correct there.
act runs each service as a separate container on a user-defined docker
network shared with the job container. Nothing is published on the job's
loopback; the service is reachable by its service name (the key under
services:), resolved by docker's embedded DNS. Under act the host is
postgres, not localhost. The giveaway is the error text itself: it
retries ::1 and 127.0.0.1 — loopback — while the healthy service sits
one hop away on the act network.
Fix that is correct in BOTH worlds — parameterise the host with a per-runner
default (vars is legal in step env and, unlike env, in job-level if):
YAML
Locally: act … --var DB_HOST=postgres. On GitHub vars.DB_HOST is unset, the
expression falls back to localhost, and the workflow is unchanged.
Sanity checks: docker network inspect <act-…-test-network> lists both
containers; getent hosts postgres resolves inside the job container; and a
service that is healthy in act's log yet "refused" from the job is always
this networking difference, never a bad healthcheck.
Checklist