Issue description
The executedmigrations
table will contain the datetime of the execution in the daterun
column and this would be then used for finding the latest executed migration if you ran ./apex migrations:down
. The problem is, if you ran previous migrations at once before, this will not provide a sufficient way to select the latest migration run. Instead it will pick a random one executed in the exact second of the truly last executed one.
Example
Code
namespace AbterPhp\Users\Databases\Migrations;
// ...
class Init extends Migration
{
// ...
public static function getCreationDate(): DateTime
{
return DateTime::createFromFormat(DateTime::ATOM, '2019-02-28T21:00:00+00:00');
}
// ...
}
namespace AbterPhp\Pages\Databases\Migrations;
// ...
class Init extends Migration
{
// ...
public static function getCreationDate(): DateTime
{
return DateTime::createFromFormat(DateTime::ATOM, '2019-02-28T21:01:00+00:00');
}
// ...
}
namespace AbterPhp\Files\Databases\Migrations;
// ...
class Init extends Migration
{
// ...
public static function getCreationDate(): DateTime
{
return DateTime::createFromFormat(DateTime::ATOM, '2019-02-28T22:00:00+00:00');
}
// ...
}
namespace AbterPhp\Contact\Databases\Migrations;
// ...
class Init extends Migration
{
// ...
public static function getCreationDate(): DateTime
{
return DateTime::createFromFormat(DateTime::ATOM, '2019-02-28T23:00:00+00:00');
}
// ...
}
Database
| migration | daterun |
--------------| -----------|
AbterPhp\Users\Databases\Migrations\Init | 2019-03-04 12:03:43 |
AbterPhp\Contact\Databases\Migrations\Init | 2019-03-04 12:03:44 |
AbterPhp\Files\Databases\Migrations\Init | 2019-03-04 12:03:44 |
AbterPhp\Pages\Databases\Migrations\Init | 2019-03-04 12:03:44 |
It may any of the last 3 for migrate:down
.
Incomplete list of potential fixes
- Replace
daterun
column with a time format which will contain some high resolution time. (Backwards compatible, but requires a schema upgrade)
- Store the
getCreationDate
in a column and use that as a second sorting parameter when selecting the "last run" migration.
- Retrieve all migrations run at the same time as the "last" one and select the migration with the latest
getCreationDate
returned. (Backwards compatible and no schema upgrade necessary, but he query will be somewhat harder to understand, and could lead to problems if someone changes the getCreatedAt
value of a migration.)
- ~~Sleep 1 second before executing consecutive schema upgrades.~~ :smile:
Note: Using microseconds as high resolution time is probably enough in most cases although it might just make it harder to reproduce the issue. Giving an option to use hrtime
instead could have benefits, but only doable in PHP at the moment afaik. (https://pecl.php.net/package/hrtime, http://php.net/manual/en/function.hrtime.php) Without hrtime
precision it might make sense to combine more solutions too.
bug