Skip to content

Commit 006fef4

Browse files
Merge pull request #105 from TheDragonCode/3.x
[3.x] Isolating Action Execution
2 parents e8fe66c + 5e51e6a commit 006fef4

File tree

13 files changed

+239
-12
lines changed

13 files changed

+239
-12
lines changed

config/actions.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
|
2525
*/
2626

27-
'table' => 'migration_actions',
27+
'table' => 'migration_actions',
2828

2929
/*
3030
|--------------------------------------------------------------------------
@@ -35,7 +35,7 @@
3535
|
3636
*/
3737

38-
'path' => base_path('actions'),
38+
'path' => base_path('actions'),
3939

4040
/*
4141
|--------------------------------------------------------------------------
@@ -56,5 +56,5 @@
5656
|
5757
*/
5858

59-
'exclude' => null,
59+
'exclude' => null,
6060
];

docs/how-to-use/running.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ bar/2022_10_14_000003_test3 # 3
2222
2022_10_14_000004_test4 # 4
2323
```
2424

25+
## Isolating Action Execution
26+
27+
If you are deploying your application across multiple servers and running migrations as part of your deployment process, you likely do not want two servers attempting to migrate
28+
the database at the same time. To avoid this, you may use the `isolated` option when invoking the `migrate:actions` command.
29+
30+
When the `isolated` option is provided, Laravel will acquire an atomic lock using your application's cache driver before attempting to run your migrations. All other attempts to
31+
run the `migrate:actions` command while that lock is held will not execute; however, the command will still exit with a successful exit status code:
32+
33+
```bash
34+
php artisan migrate:actions --isolated
35+
```
36+
2537
## Split Launch Option
2638

2739
Sometimes it becomes necessary to launch actions separately, for example, to notify about the successful deployment of a project.
@@ -39,7 +51,7 @@ For backwards compatibility, the `before` parameter is set to `true` by default,
3951
```php
4052
use DragonCode\LaravelActions\Action;
4153

42-
return new class () extends Action
54+
return new class extends Action
4355
{
4456
protected $before = false;
4557

@@ -95,7 +107,7 @@ To do this, override the `$once` variable in the action file:
95107
```php
96108
use DragonCode\LaravelActions\Action;
97109

98-
return new class () extends Action
110+
return new class extends Action
99111
{
100112
protected $once = false;
101113

@@ -123,7 +135,7 @@ For this you can use the `$environment` parameter:
123135
```php
124136
use DragonCode\LaravelActions\Action;
125137

126-
return new class () extends Action
138+
return new class extends Action
127139
{
128140
/** @var string|array|null */
129141
protected $environment = 'production';
@@ -140,7 +152,7 @@ You can also specify multiple environment names:
140152
```php
141153
use DragonCode\LaravelActions\Action;
142154

143-
return new class () extends Action
155+
return new class extends Action
144156
{
145157
/** @var string|array|null */
146158
protected $environment = ['testing', 'staging'];
@@ -163,7 +175,7 @@ For this you can use the `$except_environment` parameter:
163175
```php
164176
use DragonCode\LaravelActions\Action;
165177

166-
return new class () extends Action
178+
return new class extends Action
167179
{
168180
/** @var string|array|null */
169181
protected $exceptEnvironment = 'production';
@@ -180,7 +192,7 @@ You can also specify multiple environment names:
180192
```php
181193
use DragonCode\LaravelActions\Action;
182194

183-
return new class () extends Action
195+
return new class extends Action
184196
{
185197
/** @var string|array|null */
186198
protected $exceptEnvironment = ['testing', 'staging'];
@@ -205,7 +217,7 @@ will reduce the time it takes to create the action.
205217
```php
206218
use DragonCode\LaravelActions\Action;
207219

208-
return new class () extends Action
220+
return new class extends Action
209221
{
210222
protected $transactions = true;
211223

src/Concerns/Isolatable.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DragonCode\LaravelActions\Concerns;
6+
7+
use DragonCode\LaravelActions\Constants\Options;
8+
use DragonCode\LaravelActions\Services\Mutex;
9+
10+
trait Isolatable
11+
{
12+
protected function isolationMutex(): Mutex
13+
{
14+
return $this->getLaravel()->make(Mutex::class);
15+
}
16+
17+
protected function isolatedStatusCode(): int
18+
{
19+
if ($isolate = $this->getIsolateOption()) {
20+
return is_numeric($isolate) ? $isolate : self::SUCCESS;
21+
}
22+
23+
return self::SUCCESS;
24+
}
25+
26+
protected function getIsolateOption(): int|bool
27+
{
28+
return $this->hasIsolateOption() ? $this->option(Options::ISOLATED) : false;
29+
}
30+
31+
protected function hasIsolateOption(): bool
32+
{
33+
return $this->hasOption(Options::ISOLATED) && $this->option(Options::ISOLATED);
34+
}
35+
}

src/Concerns/Optionable.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ trait Optionable
1818
Options::CONNECTION,
1919
Options::FORCE,
2020
Options::MUTE,
21+
Options::ISOLATED,
2122
];
2223

2324
protected function configure(): void
@@ -49,6 +50,7 @@ protected function availableOptions(): array
4950
[Options::REALPATH, null, InputOption::VALUE_NONE, 'Indicate any provided action file paths are pre-resolved absolute path'],
5051
[Options::STEP, null, InputOption::VALUE_OPTIONAL, 'Force the actions to be run so they can be rolled back individually'],
5152
[Options::MUTE, null, InputOption::VALUE_NONE, 'Turns off the output of informational messages'],
53+
[Options::ISOLATED, null, InputOption::VALUE_OPTIONAL, 'Do not run the actions command if another instance of the actions command is already running', false],
5254
];
5355
}
5456

src/Console/Command.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@
55
namespace DragonCode\LaravelActions\Console;
66

77
use DragonCode\LaravelActions\Concerns\ConfirmableTrait;
8+
use DragonCode\LaravelActions\Concerns\Isolatable;
89
use DragonCode\LaravelActions\Concerns\Optionable;
910
use DragonCode\LaravelActions\Processors\Processor;
1011
use DragonCode\LaravelActions\Values\Options as OptionsDto;
1112
use Illuminate\Console\Command as BaseCommand;
1213
use Illuminate\Container\Container;
14+
use Symfony\Component\Console\Input\InputInterface;
15+
use Symfony\Component\Console\Output\OutputInterface;
1316

1417
abstract class Command extends BaseCommand
1518
{
1619
use ConfirmableTrait;
20+
use Isolatable;
1721
use Optionable;
1822

1923
protected Processor|string $processor;
@@ -24,10 +28,28 @@ public function handle(): int
2428
$this->resolveProcessor()->handle();
2529
$this->forgetProcessor();
2630

27-
return 0;
31+
return self::SUCCESS;
2832
}
2933

30-
return 1;
34+
return self::FAILURE;
35+
}
36+
37+
protected function execute(InputInterface $input, OutputInterface $output): int
38+
{
39+
if ($this->getIsolateOption() !== false && ! $this->isolationMutex()->create($this)) {
40+
$this->comment(sprintf('The [%s] command is already running.', $this->getName()));
41+
42+
return $this->isolatedStatusCode();
43+
}
44+
45+
try {
46+
return parent::execute($input, $output);
47+
}
48+
finally {
49+
if ($this->getIsolateOption() !== false) {
50+
$this->isolationMutex()->forget($this);
51+
}
52+
}
3153
}
3254

3355
protected function resolveProcessor(): Processor

src/Console/Fresh.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ class Fresh extends Command
2323
Options::PATH,
2424
Options::REALPATH,
2525
Options::MUTE,
26+
Options::ISOLATED,
2627
];
2728
}

src/Console/Migrate.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ class Migrate extends Command
2323
Options::PATH,
2424
Options::REALPATH,
2525
Options::MUTE,
26+
Options::ISOLATED,
2627
];
2728
}

src/Console/Refresh.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ class Refresh extends Command
2121
Options::PATH,
2222
Options::REALPATH,
2323
Options::MUTE,
24+
Options::ISOLATED,
2425
];
2526
}

src/Console/Reset.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ class Reset extends Command
2121
Options::PATH,
2222
Options::REALPATH,
2323
Options::MUTE,
24+
Options::ISOLATED,
2425
];
2526
}

src/Console/Rollback.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ class Rollback extends Command
2222
Options::REALPATH,
2323
Options::STEP,
2424
Options::MUTE,
25+
Options::ISOLATED,
2526
];
2627
}

0 commit comments

Comments
 (0)