This package manages database schema migrations and validations for the Performance Dashboard (perf) Cloud Spanner PostgreSQL database.
We use a Sequential Versioned SQL Migrations model to securely support delayed, batched, and zero-downtime deployments.
All database schema upgrades are written as raw SQL DDL scripts inside the migrations/ directory. Each file is named with a four-digit zero-padded sequence number:
migrations/0001_init.sql: Baseline schema containing all tablesA tracking table named schema_migrations logs all successfully applied versions:
CREATE TABLE IF NOT EXISTS schema_migrations ( version INT PRIMARY KEY, applied_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP );
On deployment, the background maintenance process runs ValidateAndMigrateNewSchema:
schema_migrations table if it doesn't exist.schema_migrations.migrations/, filtering out already applied versions.schema_migrations.schema_spanner.json and validates it against the live catalog description using assertdeep.Diff to guarantee the schema was correctly upgraded.To ensure a seamless rollout without manual database log intervention, the runner has a built-in bootstrapping logic:
schema_migrations is empty, the runner checks if the database was already initialized:autobisections table exists, it indicates the initial schema layout (version 1) has already been successfully set up.1 directly into the schema_migrations table.In production, instead of crash-looping or panicking when schemas are out of date, regular application containers (frontend and ingest) decouple database boot checks from startup:
KUBERNETES_SERVICE_HOST environment variable:/readiness HTTP endpoint. On every poll, the readiness handler checks expectedschema.VerifySchemaVersion(ctx, f.db)./readiness returns 503 Service Unavailable. Kubernetes holds the new container in the NotReady state (preventing any live traffic routing) while older containers continue serving traffic safely.Database schema is not ready yet... Waiting for migration job...) until the migration job upgrades the database, at which point /readiness turns green (200 OK) and traffic seamlessly shifts.When you need to modify the database schema, follow this step-by-step workflow:
Add a new sequential file migrations/000X_description.sql under the migrations/ folder (e.g. 0003_add_new_column.sql).
Add your DDL statements (e.g. ALTER TABLE ... ADD COLUMN ...).
Place the manual rollback DDL inside a -- Rollback SQL comment block at the top of the file:
-- Rollback SQL (For manual reference): -- ALTER TABLE Autobisections DROP COLUMN new_column; ALTER TABLE Autobisections ADD COLUMN new_column TEXT;
perf/go/autobisection/sqlautobisectionstore/schema/schema.go or other schemas) to match your new column or index.Run the regeneration scripts inside perf/ directory to automatically generate the expected SQL and JSON catalogs:
spanner/schema_spanner.go), run:cd perf/go/sql && go run ./tosql
schema_spanner.json by running:cd perf && go run ./go/sql/exportschema --out ./go/sql/expectedschema/schema_spanner.json --databaseType spanner
bazelisk test //perf/go/sql/expectedschema/...
make -C perf run-spanner-emulator) and set the printed environment variables before running unit tests.