db:upgrade

Table of contents

  1. Introduction
  2. Upgrading one feature
  3. The order, and what it retries
  4. Two replicas at once
  5. A migration that needs a decision
  6. Reference
    1. Options
    2. Errors
  7. Requirements

Introduction

db:upgrade applies the pending migrations of every feature, or of one. It never writes new scripts. Run it after you pull code, or after db:migrate wrote new files.

splent db:upgrade
    splent_feature_notes -> 990210b54b52
    splent_feature_reports -> 126da35a357f

Each applied feature prints its new revision, records it in splent_migrations and moves to migrated. A declared feature that ships no migrations moves to migrated too, since it has nothing to apply.


Upgrading one feature

splent db:upgrade splent_feature_notes

A feature can be named notes, splent_feature_notes, splent_feature_notes@v1.2.0 or splent-io/splent_feature_notes@v1.2.0. For a feature that ships no migrations it prints <feature> has no migrations, nothing to apply. and exits 0.


The order, and what it retries

db:upgrade visits the features in UVL order and retries what failed UVL DEPENDENCY ORDER Pass 1 every feature Pass 2 what failed notes shop gallery reports shop applied fails, no gallery_item applied applied applied retried A pass that applies nothing ends the run with exit 1.
On a fresh database shop can run before gallery, whose table it references. Each new pass retries only what failed, as long as the last one applied something.

Features migrate in the UVL dependency order that feature:order shows, each after the features it depends on and every refiner after its base. The order in pyproject.toml plays no part.

A migration may still reference the table of a feature it does not depend on, so on a fresh database it can fail first. Then you see retrying <features> now that the rest has migrated, and each new pass retries what failed while the last one applied something. What still fails ends the run with Error: Migration upgrade failed for: <features>.


Two replicas at once

The whole upgrade holds a named lock of the database server, GET_LOCK('splent_migrate:<database>') on MariaDB. When two replicas start together, the second waits and then finds nothing to apply.

    another db:upgrade is migrating this database, waiting for it (lock splent_migrate:<database>)...

It waits up to --lock-timeout seconds, 600 by default, and then exits 1 having migrated nothing. A database without named locks, such as SQLite, runs without one.

The product’s start passes --fresh-marker /tmp/splent_fresh_db. The file is created when the database had no table but splent_migrations, decided under the lock, so only the replica that migrates an empty database seeds it. See Migrating when the product starts.


A migration that needs a decision

Some migrations need a value only you know. Say notes0002_visibility adds a visibility column, and the notes already there need one. With notes in the table and NOTES_MIGRATION_LEGACY_VISIBILITY empty, it stops before it touches the table.

notes0002_visibility found 3 existing notes and NOTES_MIGRATION_LEGACY_VISIBILITY is empty, so it does not know who may read them. Declare NOTES_MIGRATION_LEGACY_VISIBILITY in the product's [tool.splent.config]. Then bring it into the environment this migration reads: in development run splent product:env --merge --dev and then splent db:upgrade again, in production rebuild and deploy, and the container applies the migration when it starts.

In development, declare the value, merge it into docker/.env and migrate again. No restart is needed.

[tool.splent.config]
NOTES_MIGRATION_LEGACY_VISIBILITY = "private"
splent product:env --merge --dev
splent db:upgrade

In production, declare it the same way, rebuild with product:build and deploy with product:deploy. The container migrates when it starts. On a host that runs the bundle without SPLENT, add the key to deploy/.env by hand, where it is kept.


Reference

Options

Option Description
FEATURE Optional. Only this feature
--fresh-marker PATH Create this file when the database was empty before the upgrade, and remove it when it was not
--lock-timeout SECONDS How long to wait for another db:upgrade on the same database. 600 by default

Errors

Message What to do
❌ <feature> is out of sync with the database. The database is at a revision the installed code lacks, usually after pinning an older release. Take one of the ways out it lists, feature:unlock, db:rollback --to-base or db:reset
Error: Another db:upgrade held the migration lock ... Find the connection with SELECT IS_USED_LOCK('splent_migrate:<database>') and SHOW PROCESSLIST
❌ No migrations directory found for '<feature>'. The feature is not declared, or has no migrations/ folder
Error: Cannot read the features of <product>/pyproject.toml: <reason> Fix the TOML, or the feature list it names

A feature with migrations/ and no models module is skipped silently.


Requirements

  • A selected product (SPLENT_APP), and a reachable database.
  • Migration scripts in each feature’s migrations/versions/.

Back to top

splent. Distributed by an LGPL license v3. Contact us: drorganvidez@us.es