jackc / tern

The SQL Fan's Migrator
MIT License
925 stars 68 forks source link

Race condition with initial migration #19

Closed Kaali closed 4 years ago

Kaali commented 4 years ago

https://github.com/jackc/tern/blob/1ae91883a318df7dc1582d4ea815a5380cc43e44/migrate/migrate.go#L83 is run without locking, which means that https://github.com/jackc/tern/blob/1ae91883a318df7dc1582d4ea815a5380cc43e44/migrate/migrate.go#L372-L377 can fail if multiple migrations are running at the same time.

Here's an example log where three Go services are all running migration for an empty database:

2020-03-03 12:33:43.974 UTC [72] ERROR:  relation "version" does not exist at character 21
2020-03-03 12:33:43.974 UTC [72] STATEMENT:  select version from version
2020-03-03 12:33:43.980 UTC [74] ERROR:  relation "version" does not exist at character 21
2020-03-03 12:33:43.980 UTC [74] STATEMENT:  select version from version
2020-03-03 12:33:43.984 UTC [74] ERROR:  duplicate key value violates unique constraint "pg_type_typname_nsp_index"
2020-03-03 12:33:43.984 UTC [74] DETAIL:  Key (typname, typnamespace)=(version, 2200) already exists.
2020-03-03 12:33:43.984 UTC [74] STATEMENT:
create table if not exists version(version int4 not null);
|  
| insert into version(version)
| select 0
| where 0=(select count(*) from version);

for the caller it seems like the migration is failing, even though one of the migrations is running and can succeed.

I would expect that this part is also under the migration advisory lock. Or that the error can be ignored by the caller, e.g. using a specific error value.

jackc commented 4 years ago

Should be fixed in 0189c515b2b60790fa07d7cd5c529db814536310.