mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-06 10:59:59 +00:00
Swarm Nextcloud#3 on main 748189e890 (job 117182318941) wedged the
OpenProject schema: the convergence check gave up after 74 attempts
while the seeder kept exiting 1, first with
`relation "ar_internal_metadata" already exists` from its structure
load, then with `relation "announcements" already exists` on every
`db:migrate`.
The seeder (`docker/prod/seeder`) loads `db/structure.sql` through
psql, statement by statement, when `\dt` finds no relation. In swarm,
`depends_on` is ignored, so web and worker start alongside it and poll
`await_migrations.sh`. That gate called
`rails db:abort_if_pending_migrations`, which runs
`migration_context.open`, i.e. `Migrator.new`, whose constructor
executes `schema_migration.create_table` and
`internal_metadata.create_table` (Rails 8.0.4,
activerecord/lib/active_record/migration.rb:1430-1431). The seeder
saw an empty database at 05:33:20; by 05:33:38 the gate had created
`ar_internal_metadata`, the structure load aborted at line 255 with
everything alphabetically before it already committed, and every
later attempt took the migrate path into tables that already existed.
Probe with `rails db:migrate:status` instead. It aborts while
`schema_migrations` is missing and otherwise only reads the recorded
versions (database_tasks.rb:303, migration.rb:1318); the gate treats
any `down` row as pending.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
44 lines
1.5 KiB
Bash
Executable File
44 lines
1.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Wait for the seeder's migrations, then exec the app entrypoint.
|
|
#
|
|
# Swarm ignores depends_on, so web and worker would start while the seeder is
|
|
# still migrating and die on ActiveRecord::PendingMigrationError.
|
|
#
|
|
# The wait is bounded on purpose. The probe fails both for pending migrations
|
|
# and for an unreachable database, so an unbounded loop would spin forever
|
|
# whenever the database is down. Past the deadline the entrypoint starts regardless,
|
|
# which is exactly today's behaviour: the worst case stays the crash loop that
|
|
# already exists, never a service that refuses to come up.
|
|
#
|
|
# Argv:
|
|
# $1 deadline_seconds -- how long to wait before starting anyway
|
|
# $2 poll_seconds -- sleep between probes
|
|
# $3.. entrypoint -- the upstream start command to exec
|
|
set -euo pipefail
|
|
|
|
deadline_seconds="${1:?deadline_seconds required}"
|
|
poll_seconds="${2:?poll_seconds required}"
|
|
shift 2
|
|
[ "$#" -gt 0 ] || {
|
|
echo "await_migrations: entrypoint required" >&2
|
|
exit 2
|
|
}
|
|
|
|
schema_is_current() {
|
|
local status
|
|
status=$(bundle exec rails db:migrate:status 2>/dev/null) || return 1
|
|
! grep -q -E '^[[:space:]]*down[[:space:]]' <<<"$status"
|
|
}
|
|
|
|
deadline=$(($(date +%s) + deadline_seconds))
|
|
while [ "$(date +%s)" -lt "$deadline" ]; do
|
|
if schema_is_current; then
|
|
echo "await_migrations: schema is current, starting $1"
|
|
exec "$@"
|
|
fi
|
|
sleep "$poll_seconds"
|
|
done
|
|
|
|
echo "await_migrations: deadline of ${deadline_seconds}s reached, starting $1 regardless" >&2
|
|
exec "$@"
|