Migrate (On only one server out of n) #41559
Replies: 3 comments 3 replies
-
I assume you are sharing one database server? Do you also share one caching server i.e Redis,Memcached,Dynamodb? First thing you need is to define a cache store in // config/cache.php
// ...
/*
|----------------------------------------------------------------------
| Migration Mutex Cache Store
|----------------------------------------------------------------------
|
| The name of the cache store where the migration mutex will
| be aquired when migrating the database.
|
*/
'migration_mutex_store' => env('CACHE_MIGRATION_MUTEX_STORE'),
'stores' => [
// ...
'sync' => [
'driver' => 'database',
'table' => 'cache',
'connection' => null, // probably it would be best if you had different connection for private use, instead of the one you use to serve you clients, you know - just in case.
],
// ...
], Then we can create a migrate command which will extend the original implementation but first it will try to acquire lock before migrating: // app/Commands/MigrateCommand.php
<?php
namespace App\Console\Commands;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Database\Console\Migrations\MigrateCommand as IlluminateMigrateCommand;
use Illuminate\Database\Migrations\Migrator;
class MigrateCommand extends IlluminateMigrateCommand
{
/**
* Create a new migration command instance.
*
* @return void
*/
public function __construct()
{
$this->signature .= '{--mutex : Migrate only when no mutex is present.}
{--mutex-store= : The cache store to be used to acquire the mutex.}';
parent::__construct(app('migrator'), app(Dispatcher::class));
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$lock = $this->acquireLock();
if ($lock && ! $lock->get()) {
$store = $this->getMutexStore();
$this->error("Unable to aquire cache lock [$store] for migrating, aborting.");
return 1;
}
try {
$exitCode = parent::handle();
} finally {
if ($lock) {
$lock->release();
}
}
return $exitCode;
}
/**
* Aquire the mutex lock.
*
* @return \Illuminate\Cache\Lock|false
*/
public function acquireLock()
{
if (! $this->option('mutex')) {
return false;
}
/** @var \Illuminate\Contracts\Cache\LockProvider $store */
$store = $this->laravel->make('cache')->store($this->getMutexStore());
return $store->lock('migrating');
}
/**
* Get the cache store name where the mutex will be stored.
*
* @return string
*/
public function getMutexStore()
{
return $this->option('mutex-store')
?? $this->laravel->make('config')->get('cache.migration_mutex_store')
?? $this->laravel->make('config')->get('cache.default');
}
} Our command should now be registered automatically, if that is not the case go in Now when you want to migrate once you run Just so you know, I did not test this on multiple servers but instead with 4 terminals running the same command in a while loop. And it is working as expected. |
Beta Was this translation helpful? Give feedback.
-
same issue for initcontainers in kubernetes laravel/ideas#1645 |
Beta Was this translation helpful? Give feedback.
-
or #38887 |
Beta Was this translation helpful? Give feedback.
-
Hitting an interesting issue, where we took our AWS setup from 1/at-a-time to half-at-a-time. Mainly because many servers, a more popular platform that deploying one at a time was taking forever.
Now if 4 servers attempt to release at same point - chances are they will migrate at same time and fail. I tried random sleeps in scripts to prevent same-time (it was hacky as hell)
I dug into AWS and it doesn't support a one first, then half later.
So to the idea. Wouldn't it be cool to have like
php artisan migrate --on-one-server
or something? It would use the same locking behavior that cron locks do in order to isolate to one server. So we can have a fast deploy with only 1 server migrating.Beta Was this translation helpful? Give feedback.
All reactions