Skip to content

Commit 04ac8e1

Browse files
Merge pull request #134 from TheDragonCode/4.x
Added asynchronous actions
2 parents dcfaf17 + 9a83400 commit 04ac8e1

File tree

16 files changed

+316
-15
lines changed

16 files changed

+316
-15
lines changed

composer.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@
7171
"autoload": {
7272
"psr-4": {
7373
"DragonCode\\LaravelActions\\": "src"
74-
}
74+
},
75+
"classmap": [
76+
"polyfill"
77+
]
7578
},
7679
"autoload-dev": {
7780
"psr-4": {

config/actions.php

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

27-
'table' => 'actions',
27+
'table' => '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,40 @@
5656
|
5757
*/
5858

59-
'exclude' => null,
59+
'exclude' => null,
60+
61+
/*
62+
|--------------------------------------------------------------------------
63+
| Queue
64+
|--------------------------------------------------------------------------
65+
|
66+
| This option specifies the queue settings that will process
67+
| asynchronous actions.
68+
|
69+
*/
70+
71+
'queue' => [
72+
/*
73+
|--------------------------------------------------------------------------
74+
| Queue Connection
75+
|--------------------------------------------------------------------------
76+
|
77+
| This parameter defines the default connection.
78+
|
79+
*/
80+
81+
'connection' => env('ACTIONS_QUEUE_CONNECTION', env('QUEUE_CONNECTION', 'sync')),
82+
83+
/*
84+
|--------------------------------------------------------------------------
85+
| Queue Name
86+
|--------------------------------------------------------------------------
87+
|
88+
| This parameter specifies the name of the queue to which asynchronous
89+
| jobs will be sent.
90+
|
91+
*/
92+
93+
'name' => env('ACTIONS_QUEUE_NAME'),
94+
],
6095
];

docs/how-to-use/running.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,33 @@ return new class extends Action
225225
}
226226
};
227227
```
228+
229+
## Asynchronous Call
230+
231+
In some cases, it becomes necessary to execute actions in an asynchronous manner without delaying the deployment process.
232+
233+
To do this, you need to override the `$async` property in the action class:
234+
235+
```php
236+
use DragonCode\LaravelActions\Action;
237+
238+
return new class extends Action
239+
{
240+
protected bool $async = true;
241+
242+
public function __invoke(): void
243+
{
244+
// some code
245+
}
246+
};
247+
```
248+
249+
In this case, the action file that defines this parameter will run asynchronously using the `DragonCode\LaravelActions\Jobs\ActionJob` class.
250+
251+
The name of the connection and queue can be changed through the [settings](https://github.com/TheDragonCode/laravel-actions/tree/main/config).
252+
253+
::: Info
254+
We remind you that in this case the [queuing system](https://laravel.com/docs/queues) must work in your application.
255+
256+
Using Laravel version 8.37 and above, checking for the [uniqueness](https://laravel.com/docs/10.x/queues#unique-jobs) of the execution is supported.
257+
:::

polyfill/ShouldBeUnique.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Illuminate\Contracts\Queue;
6+
7+
if (! interface_exists(ShouldBeUnique::class)) {
8+
interface ShouldBeUnique
9+
{
10+
}
11+
}

src/Action.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ abstract class Action extends Migration
5757
*/
5858
protected bool $before = true;
5959

60+
/**
61+
* Defines whether the action will run synchronously or asynchronously.
62+
*
63+
* @var bool
64+
*/
65+
protected bool $async = false;
66+
6067
/**
6168
* Determines the type of launch of the action.
6269
*
@@ -130,6 +137,16 @@ public function hasBefore(): bool
130137
return $this->before;
131138
}
132139

140+
/**
141+
* Defines whether the action will run synchronously or asynchronously.
142+
*
143+
* @return bool
144+
*/
145+
public function isAsync(): bool
146+
{
147+
return $this->async;
148+
}
149+
133150
/**
134151
* Method to be called when the job completes successfully.
135152
*

src/Concerns/Optionable.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ protected function availableOptions(): array
5151
[Options::STEP, null, InputOption::VALUE_OPTIONAL, 'Force the actions to be run so they can be rolled back individually'],
5252
[Options::MUTE, null, InputOption::VALUE_NONE, 'Turns off the output of informational messages'],
5353
[Options::ISOLATED, null, InputOption::VALUE_OPTIONAL, 'Do not run the actions command if another instance of the actions command is already running', false],
54+
[Options::SYNC, null, InputOption::VALUE_OPTIONAL, 'Makes all actions run synchronously', false],
5455
];
5556
}
5657

src/Console/Actions.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ class Actions extends Command
2424
Options::REALPATH,
2525
Options::MUTE,
2626
Options::ISOLATED,
27+
Options::SYNC,
2728
];
2829
}

src/Constants/Options.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,6 @@ class Options
2323
public const REALPATH = 'realpath';
2424

2525
public const STEP = 'step';
26+
27+
public const SYNC = 'sync';
2628
}

src/Jobs/ActionJob.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DragonCode\LaravelActions\Jobs;
6+
7+
use DragonCode\LaravelActions\Constants\Names;
8+
use DragonCode\LaravelActions\Constants\Options;
9+
use Illuminate\Bus\Queueable;
10+
use Illuminate\Contracts\Queue\ShouldBeUnique;
11+
use Illuminate\Contracts\Queue\ShouldQueue;
12+
use Illuminate\Foundation\Bus\Dispatchable;
13+
use Illuminate\Queue\InteractsWithQueue;
14+
use Illuminate\Queue\SerializesModels;
15+
use Illuminate\Support\Facades\Artisan;
16+
17+
class ActionJob implements ShouldQueue, ShouldBeUnique
18+
{
19+
use Dispatchable;
20+
use InteractsWithQueue;
21+
use Queueable;
22+
use SerializesModels;
23+
24+
public function __construct(
25+
public string $filename
26+
) {
27+
$this->setQueueConnection();
28+
$this->setQueueName();
29+
}
30+
31+
public function handle(): void
32+
{
33+
Artisan::call(Names::ACTIONS, [
34+
'--' . Options::PATH => $this->filename,
35+
'--' . Options::SYNC => true,
36+
]);
37+
}
38+
39+
public function uniqueId(): string
40+
{
41+
return $this->filename;
42+
}
43+
44+
protected function setQueueConnection(): void
45+
{
46+
$this->onConnection(config('actions.queue.connection'));
47+
}
48+
49+
protected function setQueueName(): void
50+
{
51+
$this->onQueue(config('actions.queue.name'));
52+
}
53+
}

src/Services/Migrator.php

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use DragonCode\LaravelActions\Action;
88
use DragonCode\LaravelActions\Contracts\Notification;
99
use DragonCode\LaravelActions\Helpers\Config;
10+
use DragonCode\LaravelActions\Jobs\ActionJob;
1011
use DragonCode\LaravelActions\Repositories\ActionRepository;
1112
use DragonCode\LaravelActions\Values\Options;
1213
use DragonCode\Support\Exceptions\FileNotFoundException;
@@ -49,6 +50,12 @@ public function runUp(string $filename, int $batch, Options $options): void
4950
$name = $this->resolveActionName($path);
5051

5152
if ($this->allowAction($action, $options)) {
53+
if ($this->hasAsync($action, $options)) {
54+
dispatch(new ActionJob($name));
55+
56+
return;
57+
}
58+
5259
$this->notification->task($name, function () use ($action, $name, $batch) {
5360
$this->hasAction($action, '__invoke')
5461
? $this->runAction($action, '__invoke')
@@ -72,19 +79,11 @@ public function runDown(string $filename, Options $options): void
7279
$name = $this->resolveActionName($path);
7380

7481
$this->notification->task($name, function () use ($action, $name) {
75-
if (! $this->hasAction($action, '__invoke') && $this->hasAction($action, 'down')) {
76-
$this->runAction($action, 'down');
77-
}
78-
82+
$this->runAction($action, 'down');
7983
$this->deleteLog($name);
8084
});
8185
}
8286

83-
protected function hasAction(Action $action, string $method): bool
84-
{
85-
return method_exists($action, $method);
86-
}
87-
8887
protected function runAction(Action $action, string $method): void
8988
{
9089
if ($this->hasAction($action, $method)) {
@@ -101,6 +100,16 @@ protected function runAction(Action $action, string $method): void
101100
}
102101
}
103102

103+
protected function hasAction(Action $action, string $method): bool
104+
{
105+
return method_exists($action, $method);
106+
}
107+
108+
protected function hasAsync(Action $action, Options $options): bool
109+
{
110+
return ! $options->sync && $action->isAsync();
111+
}
112+
104113
protected function runMethod(Action $action, string $method, bool $transactions, int $attempts): void
105114
{
106115
$callback = fn () => $this->laravel->call([$action, $method]);

0 commit comments

Comments
 (0)