I work on a project that sometimes require data change for all customers. Since each customer have it’s own database, we always end up working on a script to run it across the whole client-base.
Another common thing during these script development is that you want to run for a specific customer (testing database) first, see the results before you roll it out for every customer. On this article, I’m going to show how I built an abstract command that makes these processes easier.
1- The Abstract Command
The abstract command will be the one actually implementing the
handle method. It consists in running a job (synchronously) for a specific tenant or dispatching one job per tenant. This allows to check the result of the script immediately during tests while being able to run multiple workers to process every tenant in parallel when it’s ready to roll out.
2- The Concrete Command
A concrete command will have to do 2 things:
- Setup the command signature;
- Instantiate the Job to be executed;
The following snippet is an example of how simple it is to create a new upgrade command.
3- The Abstract Job
Just like the upgrade command, every job class will have some pieces of code that I don’t want to duplicate. Let’s extract all of that into an abstract Job. It is the Job’s responsibility to:
- Make sure a Tenant is provided.
- Run the migration process inside a database transaction.
- Define the amount of attempt to only once.
If you want to see how I establish the database connection, check out this article: Multi Tenancy with Laravel.
4- The Concrete Job
The Concrete Job should extend the abstract (obviously) and implement the
run method, which should contain the data migration logic.
5- Wrapping it up
To get everything up and running, just make sure to register the
App\Console\Kernel.php class and run it through artisan.
php artisan upgrade:menu --database=my_test_database
Once the script is ready to go live, just run it with the flag
--all and get the workers up.
php artisan upgrade:menu --all
php artisan queue:work
Of course, you can always run multiple
queue:work to run it in parallel.