Skip to content

Commit 137a35d

Browse files
authored
Document Deployment-compatible migrations (#2987)
1 parent 5fb7af3 commit 137a35d

1 file changed

Lines changed: 27 additions & 20 deletions

File tree

contributing/MIGRATIONS.md

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,32 +11,39 @@ alembic revision -m "<some message>" --autogenerate
1111

1212
Then adjust the generated migration if needed.
1313

14-
## PostgreSQL enums
14+
## Deployment-compatible migrations
1515

16-
If you modify any enums used in SQLAlchemy models, you will need to set up PostgreSQL
17-
in order to generate a PostgreSQL-specific enum migration.
16+
The `dstack` server claims to support multi-replica setups with zero-downtime deployments.
17+
This means DB migrations should not make changes that break old replicas.
18+
Incompatible changes should be introduced in multiple stages (releases), following
19+
the [expand and contract pattern](https://www.prisma.io/dataguide/types/relational/expand-and-contract-pattern).
1820

19-
1. Run PostgreSQL.
21+
**Note**: If it's impossible to make the migration compatible with older versions, the PR should say so explicitly, so that the change is planned and released with the migration notice.
2022

21-
```shell
22-
docker run --rm -p 5432:5432 -e POSTGRES_PASSWORD=password postgres
23-
```
23+
Below are some common changes and how to make them.
2424

25-
1. Create a database for `dstack`.
25+
### Removing a column
2626

27-
```shell
28-
psql -h localhost -U postgres --command "CREATE DATABASE dstack"
29-
```
27+
1. First release:
28+
* Stop reading the column. In SQLAlchemy this can be done by setting `deferred=True` on a model field.
29+
2. Second release:
30+
* Drop the column.
3031

31-
1. Run `dstack server` once to create the previous database schema.
32+
### Changing a column
3233

33-
```shell
34-
DSTACK_DATABASE_URL=postgresql+asyncpg://postgres:password@localhost:5432/dstack dstack server
35-
```
34+
These steps apply to **renaming a column** or **changing the type of a column**
3635

37-
1. Generate the migration.
36+
1. First release:
37+
* Introduce a new column with the new type.
38+
* Write to both the new and the old column.
39+
2. Second release:
40+
* Migrate data from the old column to the new column.
41+
* Start reading the new column.
42+
* Stop reading the old column.
43+
* Stop writing to the old column.
44+
3. Third release:
45+
* Drop the old column.
3846

39-
```shell
40-
cd src/dstack/_internal/server/
41-
DSTACK_DATABASE_URL=postgresql+asyncpg://postgres:password@localhost:5432/dstack alembic revision -m "<some message>" --autogenerate
42-
```
47+
### Altering multiple tables
48+
49+
Altering a table requires Postgres to [take an ACCESS EXCLUSIVE lock](https://www.postgresql.org/docs/current/sql-altertable.html). (This applies not only to statements that rewrite the tables but also to statements that modify tables metadata.) Altering multiple tables can cause deadlocks due to conflict with read operations since the `dstack` server does not define an order for read operations. Altering multiple tables should be done in separate transactions/migrations.

0 commit comments

Comments
 (0)