On first boot with a fresh Postgres volume, osprey-worker can crash during startup while the rest of the stack comes up healthy:
psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "pg_type_typname_nsp_index"
raised from CREATE TYPE job_status AS ENUM (...).
Both the worker and the UI API run metadata.create_all(new_engine) at startup:
|
metadata.create_all(new_engine) |
and the job_status enum is declared with create_type=True:
|
Enum(BulkActionJobStatus, name='job_status', create_type=True, values_callable=lambda x: [e.value for e in x]), |
SQLAlchemy's enum creation is check-then-create, which isn't concurrency-safe: on a fresh volume both processes see the type missing, both issue CREATE TYPE, and the loser dies. docker start osprey-worker recovers (the type exists by then), after which events process normally.
This only bites on first boot with a fresh volume—which is exactly the newcomer path, since demo.sh removes old volumes on every run. When the worker loses the race, the demo opens on an empty UI with no events processing. It may also explain #213, where events were produced and consumed but the event stream stayed empty, inconsistently across runs.
Possible fixes: serialize schema creation behind a Postgres advisory lock, catch the duplicate-type error and continue, or make one service the sole owner of create_all.
Observed 2026-07-14 during a clean ./demo.sh run while verifying the 1.1 docs.
On first boot with a fresh Postgres volume,
osprey-workercan crash during startup while the rest of the stack comes up healthy:raised from
CREATE TYPE job_status AS ENUM (...).Both the worker and the UI API run
metadata.create_all(new_engine)at startup:osprey/osprey_worker/src/osprey/worker/lib/storage/postgres.py
Line 63 in 958900a
and the
job_statusenum is declared withcreate_type=True:osprey/osprey_worker/src/osprey/worker/lib/storage/bulk_action_task.py
Line 39 in 958900a
SQLAlchemy's enum creation is check-then-create, which isn't concurrency-safe: on a fresh volume both processes see the type missing, both issue
CREATE TYPE, and the loser dies.docker start osprey-workerrecovers (the type exists by then), after which events process normally.This only bites on first boot with a fresh volume—which is exactly the newcomer path, since
demo.shremoves old volumes on every run. When the worker loses the race, the demo opens on an empty UI with no events processing. It may also explain #213, where events were produced and consumed but the event stream stayed empty, inconsistently across runs.Possible fixes: serialize schema creation behind a Postgres advisory lock, catch the duplicate-type error and continue, or make one service the sole owner of
create_all.Observed 2026-07-14 during a clean
./demo.shrun while verifying the 1.1 docs.