Paul Gadal
12/02/2025, 8:43 AMc 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/site-packages/sqlalchemy/util/langhelpers.py", line 224, in __exit__
Dec 1 19:50:20 dtftlp11 bash[2690]: raise exc_value.with_traceback(exc_tb)
Dec 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/site-packages/sqlalchemy/pool/impl.py", line 175, in _do_get
Dec 1 19:50:20 dtftlp11 bash[2690]: return self._create_connection()
Dec 1 19:50:20 dtftlp11 bash[2690]: ^^^^^^^^^^^^^^^^^^^^^^^^^
Dec 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/site-packages/sqlalchemy/pool/base.py", line 388, in _create_connection
Dec 1 19:50:20 dtftlp11 bash[2690]: return _ConnectionRecord(self)
Dec 1 19:50:20 dtftlp11 bash[2690]: ^^^^^^^^^^^^^^^^^^^^^^^
Dec 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/site-packages/sqlalchemy/pool/base.py", line 673, in __init__
Dec 1 19:50:20 dtftlp11 bash[2690]: self.__connect()
Dec 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/site-packages/sqlalchemy/pool/base.py", line 899, in __connect
Dec 1 19:50:20 dtftlp11 bash[2690]: with util.safe_reraise():
Dec 1 19:50:20 dtftlp11 bash[2690]: ^^^^^^^^^^^^^^^^^^^
Dec 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/site-packages/sqlalchemy/util/langhelpers.py", line 224, in __exit__
Dec 1 19:50:20 dtftlp11 bash[2690]: raise exc_value.with_traceback(exc_tb)
Dec 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/site-packages/sqlalchemy/pool/base.py", line 895, in __connect
Dec 1 19:50:20 dtftlp11 bash[2690]: self.dbapi_connection = connection = pool._invoke_creator(self)
Dec 1 19:50:20 dtftlp11 bash[2690]: ^^^^^^^^^^^^^^^^^^^^^^^^^^
Dec 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/site-packages/sqlalchemy/engine/create.py", line 661, in connect
Dec 1 19:50:20 dtftlp11 bash[2690]: return dialect.connect(*cargs, **cparams)
Dec 1 19:50:20 dtftlp11 bash[2690]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Dec 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/site-packages/sqlalchemy/engine/default.py", line 629, in connect
Dec 1 19:50:20 dtftlp11 bash[2690]: return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
Dec 1 19:50:20 dtftlp11 bash[2690]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Dec 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/site-packages/sqlalchemy/dialects/postgresql/asyncpg.py", line 955, in connect
Dec 1 19:50:20 dtftlp11 bash[2690]: await_only(creator_fn(*arg, **kw)),
Dec 1 19:50:20 dtftlp11 bash[2690]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Dec 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 132, in await_only
Dec 1 19:50:20 dtftlp11 bash[2690]: return current.parent.switch(awaitable) # type: ignore[no-any-return,attr-defined] # noqa: E501
Dec 1 19:50:20 dtftlp11 bash[2690]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Dec 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/site-packages/sqlalchemy/util/_concurrency_py3k.py", line 196, in greenlet_spawn
Dec 1 19:50:20 dtftlp11 bash[2690]: value = await result
Dec 1 19:50:20 dtftlp11 bash[2690]: ^^^^^^^^^^^^
Dec 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/site-packages/asyncpg/connection.py", line 2420, in connect
Dec 1 19:50:20 dtftlp11 bash[2690]: async with compat.timeout(timeout):
Dec 1 19:50:20 dtftlp11 bash[2690]: ^^^^^^^^^^^^^^^^^^^^^^^
Dec 1 19:50:20 dtftlp11 bash[2690]: File "/data/conda/envs/datafetch/lib/python3.12/asyncio/timeouts.py", line 115, in __aexit__
Dec 1 19:50:20 dtftlp11 bash[2690]: raise TimeoutError from exc_val
Dec 1 19:50:20 dtftlp11 bash[2690]: TimeoutError
then I have an internal error
prefect.exceptions.PrefectHTTPStatusError: Server error '500 Internal Server Error' for url '<http://dtftlp11.mfi.inte:4200/api/deployments/f17ba367-fe08-4cf1-a6b6-af58e60eddcf>'Marvin
12/02/2025, 8:44 AMMarvin
12/02/2025, 8:46 AMcurl -sS <http://dtftlp11.mfi.inte:4200/api/health>
curl -sS -i <http://dtftlp11.mfi.inte:4200/api/ready>
- /api/health should return 200 when the server process is up.
- /api/ready checks DB connectivity. If it’s not 200, the API can’t reach the database.
2) Verify DB connectivity from the API host
- Confirm you can connect to Postgres from the same host the API runs on:
psql "host=<db-host> port=<port> dbname=<prefect_db> user=<user> password=<password>" -c "select 1"
If this fails, it’s networking/auth/SSL/firewall/DNS.
3) Confirm Prefect 3.x DB configuration (server side)
Make sure your Prefect API is configured with an async Postgres URL and appropriate timeouts. In Prefect 3.x, set these environment variables for the API process:
- Use an async driver (required):
PREFECT_SERVER_DATABASE_CONNECTION_URL="postgresql+asyncpg://<user>:<password>@<host>:<port>/<database>"
If your password has special characters, URL-encode them.
- If you prefer component settings instead of a full URL:
PREFECT_SERVER_DATABASE_DRIVER="postgresql+asyncpg"
PREFECT_SERVER_DATABASE_HOST="<host>"
PREFECT_SERVER_DATABASE_PORT="5432"
PREFECT_SERVER_DATABASE_USER="<user>"
PREFECT_SERVER_DATABASE_PASSWORD="<password>"
PREFECT_SERVER_DATABASE_NAME="<database>"
- Timeouts and pool (bump these if you see timeouts under load or slow networks):
PREFECT_SERVER_DATABASE_CONNECTION_TIMEOUT="15.0" # connect timeout (seconds)
PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_TIMEOUT="60.0" # wait time for a pooled connection
PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_SIZE="10"
PREFECT_SERVER_DATABASE_SQLALCHEMY_MAX_OVERFLOW="20"
- If you’re behind PgBouncer (transaction mode), avoid prepared statement issues:
PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_STATEMENT_CACHE_SIZE="0"
PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_PREPARED_STATEMENT_CACHE_SIZE="0"
- TLS (if your Postgres requires it):
PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_TLS_ENABLED="true"
PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_TLS_CA_FILE="/path/to/ca.crt"
PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_TLS_CERT_FILE="/path/to/client.crt"
PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_TLS_KEY_FILE="/path/to/client.key"
PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_TLS_CHECK_HOSTNAME="true"
4) Restart the API after config changes
- After adjusting env vars for the API, restart the Prefect server process, then re-check:
curl -i <http://dtftlp11.mfi.inte:4200/api/ready>
5) Look for clues in logs
- Prefect API logs around the failure should show DB connection attempts and errors.
- Postgres server logs (or PgBouncer logs) will show if connections are refused, auth failures, or pool exhaustion.
Why this affects your worker/work pool
- Workers just call the API. If the API can’t query the DB, workers receive 5xx errors on endpoints like /api/deployments/<id>. Fixing the API’s DB connectivity should stop the work pool “crashes”.
A couple of questions to help us pinpoint it:
- Are you running self-hosted Prefect Server 3.x with Postgres (vs. SQLite)? Any PgBouncer in front?Marvin
12/02/2025, 8:46 AMPREFECT_SERVER_DATABASE_CONNECTION_URL (feel free to redact secrets)?
- Do /api/health and /api/ready return 200? If not, what’s the status/body?
- Any recent changes to your DB, network rules, or TLS configuration?
If you share your server env settings (mask secrets) and a snippet of API logs around the failure, I can suggest exact values to try next.Paul Gadal
12/02/2025, 8:54 AM"database": {
"sqlalchemy": {
"connect_args": {
"application_name": null,
"statement_cache_size": null,
"prepared_statement_cache_size": null,
"tls": {
"enabled": false,
"ca_file": null,
"cert_file": null,
"key_file": null,
"check_hostname": true
}
},
"pool_size": 5,
"pool_recycle": 3600,
"pool_timeout": 180,
"max_overflow": -1
},
"connection_url": "**********",
"driver": null,
"host": null,
"port": null,
"user": null,
"name": null,
"password": null,
"echo": false,
"migrate_on_start": true,
"timeout": 10,
"connection_timeout": 5
},
Maybe it could be a good option to increase some timeouts no?Marvin
12/02/2025, 8:54 AMMarvin
12/02/2025, 8:54 AMconnection_timeout is 5s — that’s the time allowed to establish a new connection (includes DNS). Bump it to 20–30s.
- Your pool_timeout is already generous at 180s (time waiting for a pooled connection), that’s fine.
- Consider slightly larger, bounded pooling so new connection attempts don’t explode under bursts:
- `pool_size`: 10 (from 5)
- `max_overflow`: 10–20 (instead of -1 which is unlimited)
- Optionally lower pool_recycle (e.g., 600–1800) to avoid occasionally stale connections lingering.
- If you’re behind PgBouncer (transaction mode), disable prepared statement caching.
Concrete env vars to try on the API (Prefect 3.x):
PREFECT_SERVER_DATABASE_CONNECTION_URL="postgresql+asyncpg://<user>:<password>@<IP-or-host>:5432/<database>"
# Make connection establishment more tolerant of DNS slowness
PREFECT_SERVER_DATABASE_CONNECTION_TIMEOUT="30.0" # was 5
# Optional: if DB queries are sometimes slow, increase statement timeout
PREFECT_SERVER_DATABASE_TIMEOUT="30.0" # was 10
# Pooling: increase capacity and bound overflow
PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_SIZE="10" # was 5
PREFECT_SERVER_DATABASE_SQLALCHEMY_MAX_OVERFLOW="15" # was -1 (unbounded)
PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_TIMEOUT="180"
PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_RECYCLE="1200"
# If using PgBouncer (transaction mode), avoid prepared statements
PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_STATEMENT_CACHE_SIZE="0"
PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_PREPARED_STATEMENT_CACHE_SIZE="0"
After applying, restart the API and check:
curl -i <http://dtftlp11.mfi.inte:4200/api/ready>
- 200 OK means the API can reach the DB; if it flips to non-200 during DNS hiccups, increasing PREFECT_SERVER_DATABASE_CONNECTION_TIMEOUT should reduce false “down” windows.
A couple of clarifying questions so I can tailor the recommendations:
- Can you switch the connection_url to use the DB’s IP (even temporarily) to confirm DNS is the root cause?
- Are you using PgBouncer in front of Postgres?
- Roughly how many concurrent API requests do you see during busy periods (to size the pool appropriately)?
If you share your redacted connection_url (hostname vs IP) and whether PgBouncer is in play, I can suggest exact values to settle on.Paul Gadal
12/02/2025, 9:27 AMMarvin
12/02/2025, 9:27 AMMarvin
12/02/2025, 9:29 AMPREFECT_SERVER_DATABASE_SQLALCHEMY_* environment variables apply to the Prefect Server API’s SQLAlchemy engine regardless of whether you’re using PostgreSQL (asyncpg) or SQLite. For PostgreSQL specifically, they’re the right knobs to tune pool behavior and connect args.
Key ones you can safely adjust with Postgres:
- Pool sizing and timeouts
- PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_SIZE
- PREFECT_SERVER_DATABASE_SQLALCHEMY_MAX_OVERFLOW
- PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_TIMEOUT
- PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_RECYCLE
- Connect-timeout and statement-timeout
- PREFECT_SERVER_DATABASE_CONNECTION_TIMEOUT (connect establishment; includes DNS)
- PREFECT_SERVER_DATABASE_TIMEOUT (statement execution)
- Postgres-specific connect args (asyncpg)
- PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_APPLICATION_NAME
- PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_STATEMENT_CACHE_SIZE
- PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_PREPARED_STATEMENT_CACHE_SIZE
- TLS fields under ...CONNECT_ARGS_TLS_* if you need SSL/mTLS
Note on names/nesting:
- Use single underscores for nesting, e.g. PREFECT_SERVER_DATABASE_SQLALCHEMY_CONNECT_ARGS_STATEMENT_CACHE_SIZE (not double underscores).
- These settings apply when your API is using an async Postgres URL like postgresql+asyncpg://....
Given intermittent DNS issues, the most impactful changes are:
- Increase connect timeout:
PREFECT_SERVER_DATABASE_CONNECTION_TIMEOUT="30.0"
- Optionally increase statement timeout if queries are slow:
PREFECT_SERVER_DATABASE_TIMEOUT="30.0"
- Right-size and bound the pool:
PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_SIZE="10"
PREFECT_SERVER_DATABASE_SQLALCHEMY_MAX_OVERFLOW="15"
PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_TIMEOUT="180"
PREFECT_SERVER_DATABASE_SQLALCHEMY_POOL_RECYCLE="1200"
And if DNS flakiness persists, consider using the DB’s IP (or a hosts file entry) in your PREFECT_SERVER_DATABASE_CONNECTION_URL to remove DNS from the critical path.