Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use opis/closure 4.0 #13

Merged
merged 9 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Note: you may refer to `README.md` for description of features.

## Dev (WIP)
- Task IDs can be given to tasks (generated or not) (https://github.com/Vectorial1024/laravel-process-async/issues/5)
- Updated to use `opis/closure` 4.0 for task details serialization (https://github.com/Vectorial1024/laravel-process-async/issues/12)
- Technically a breaking internal change, but no code change expected and downtime is expected to be almost negligible

## 0.2.0 (2025-01-04)
- Task runners are now detached from the task giver (https://github.com/Vectorial1024/laravel-process-async/issues/7)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Utilize Laravel Processes to run PHP code asynchronously, as if using Laravel Co
## What really is this?
[Laravel Processes](https://laravel.com/docs/10.x/processes) was first introduced in Laravel 10. This library wraps around `Process::start()` to let you execute code in the background to achieve async, albeit with some caveats:
- You may only execute PHP code
- Restrictions from `laravel/serializable-closure` apply (see [their README](https://github.com/laravel/serializable-closure))
- Restrictions from `opis/closure` apply (see [their README](https://github.com/opis/closure))
- Hands-off execution: no built-in result-checking, check the results yourself (e.g. via database, file cache, etc)

This library internally uses an Artisan command to run the async code, which is similar to Laravel 11 [Concurrency](https://laravel.com/docs/11.x/concurrency).
Expand Down
7 changes: 5 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
"require": {
"php": "^8.1",
"illuminate/support": "^10.0|^11.0",
"laravel/serializable-closure": "^1.0",
"loophp/phposinfo": "^1.8"
"loophp/phposinfo": "^1.8",
"opis/closure": "^4.0"
},
"require-dev": {
"phpunit/phpunit": "^10",
Expand All @@ -50,5 +50,8 @@
"Vectorial1024\\LaravelProcessAsync\\ProcessAsyncServiceProvider"
]
}
},
"config": {
"sort-packages": true
}
}
35 changes: 24 additions & 11 deletions src/AsyncTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,22 @@
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Laravel\SerializableClosure\SerializableClosure;
use LogicException;
use loophp\phposinfo\OsInfo;
use RuntimeException;

use function Opis\Closure\{serialize, unserialize};

/**
* The common handler of an AsyncTask; this can be a closure (will be wrapped inside AsyncTask) or an interface instance.
*/
class AsyncTask
{
/**
* The task to be executed in the background.
* @var SerializableClosure|AsyncTaskInterface
* @var Closure|AsyncTaskInterface
*/
private SerializableClosure|AsyncTaskInterface $theTask;
private Closure|AsyncTaskInterface $theTask;

/**
* The user-specified ID of the current task. (Null means user did not specify any ID).
Expand Down Expand Up @@ -105,17 +106,31 @@ class AsyncTask
*/
public function __construct(Closure|AsyncTaskInterface $theTask, string|null $taskID = null)
{
if ($theTask instanceof Closure) {
// convert to serializable closure first
$theTask = new SerializableClosure($theTask);
}
// opis/closure allows direct storage of closure
$this->theTask = $theTask;
if ($taskID === "") {
throw new InvalidArgumentException("AsyncTask ID cannot be empty.");
}
$this->taskID = $taskID;
}

public function __serialize(): array
{
// serialize only the necessary info to reduce runner cmd length
return [
'theTask' => $this->theTask,
'timeLimit' => $this->timeLimit,
];
}

public function __unserialize($data): void
{
[
'theTask' => $this->theTask,
'timeLimit' => $this->timeLimit,
] = $data;
}

/**
* Inside an available PHP process, runs this AsyncTask instance.
*
Expand Down Expand Up @@ -159,10 +174,8 @@ public function run(): void
}

// then, execute the task itself
if ($this->theTask instanceof SerializableClosure) {
$innerClosure = $this->theTask->getClosure();
$innerClosure();
unset($innerClosure);
if ($this->theTask instanceof Closure) {
($this->theTask)();
} else {
// must be AsyncTaskInterface
$this->theTask->execute();
Expand Down
Loading