From f2b1fd2fdd8af21c1deea8400b1aa8a67aa05863 Mon Sep 17 00:00:00 2001 From: Riley Aven Date: Wed, 26 Jun 2024 12:52:04 -0400 Subject: [PATCH] Allow checks to be serializable --- composer.json | 1 + src/Checks/Check.php | 32 +++++++++++++++++++ tests/Checks/QueueCheckTest.php | 29 +++++++++++++++++ ...ueueCheckTest__it_can_be_serialized__1.txt | 1 + ...ueCheckTest__it_can_be_unserialized__1.yml | 7 ++++ 5 files changed, 70 insertions(+) create mode 100644 tests/__snapshots__/QueueCheckTest__it_can_be_serialized__1.txt create mode 100644 tests/__snapshots__/QueueCheckTest__it_can_be_unserialized__1.yml diff --git a/composer.json b/composer.json index 131e8376..4de913a9 100644 --- a/composer.json +++ b/composer.json @@ -24,6 +24,7 @@ "illuminate/database": "^8.75|^9.0|^10.0|^11.0", "illuminate/notifications": "^8.75|^9.0|^10.0|^11.0", "illuminate/support": "^8.75|^9.0|^10.0|^11.0", + "laravel/serializable-closure": "^1.3", "nunomaduro/termwind": "^1.0|^2.0", "spatie/enum": "^3.13", "spatie/laravel-package-tools": "^1.12.1", diff --git a/src/Checks/Check.php b/src/Checks/Check.php index b81635cf..c3d1d1f7 100755 --- a/src/Checks/Check.php +++ b/src/Checks/Check.php @@ -8,6 +8,7 @@ use Illuminate\Support\Str; use Illuminate\Support\Traits\Conditionable; use Illuminate\Support\Traits\Macroable; +use Laravel\SerializableClosure\SerializableClosure; use Spatie\Health\Enums\Status; abstract class Check @@ -78,6 +79,10 @@ public function getName(): string return Str::of($baseName)->beforeLast('Check'); } + public function getRunConditions(): array { + return $this->shouldRun; + } + public function shouldRun(): bool { foreach ($this->shouldRun as $shouldRun) { @@ -119,4 +124,31 @@ public function markAsCrashed(): Result public function onTerminate(mixed $request, mixed $response): void { } + + public function __serialize(): array { + $vars = get_object_vars($this); + + $serializableClosures = []; + foreach ($vars['shouldRun'] as $shouldRun) { + $serializableClosures[] = new SerializableClosure($shouldRun); + } + + $vars['shouldRun'] = $serializableClosures; + + return $vars; + } + + public function __unserialize(array $data): void { + foreach ($data as $property => $value) { + $this->$property = $value; + } + + $unwrappedClosures = []; + + foreach($this->shouldRun as $shouldRun) { + $unwrappedClosures[] = $shouldRun->getClosure(); + } + + $this->shouldRun = $unwrappedClosures; + } } diff --git a/tests/Checks/QueueCheckTest.php b/tests/Checks/QueueCheckTest.php index 791b246f..1e8e47f4 100644 --- a/tests/Checks/QueueCheckTest.php +++ b/tests/Checks/QueueCheckTest.php @@ -8,7 +8,11 @@ use Spatie\Health\Jobs\HealthQueueJob; use function Pest\Laravel\artisan; +use function PHPUnit\Framework\assertCount; +use function PHPUnit\Framework\assertInstanceOf; use function Spatie\PestPluginTestTime\testTime; +use function Spatie\Snapshots\assertMatchesObjectSnapshot; +use function Spatie\Snapshots\assertMatchesSnapshot; beforeEach(function () { $this->queueCheck = QueueCheck::new(); @@ -109,3 +113,28 @@ expect($this->queueCheck->getQueues())->toBe([$queueName]); }); + +it('can be serialized', function() { + $check = QueueCheck::new() + ->onQueue('sync') + ->if(fn() => false); + + $result = serialize($check); + // Replace with a consistent identifier + $result = preg_replace('/s:32:"[0-9a-z]{32}";/', 's:32:"0000000000000000000000000000000000000000";', $result); + + assertMatchesSnapshot($result); +}); + +it('can be unserialized', function() { + $check = QueueCheck::new() + ->onQueue('sync') + ->if(fn() => false); + + $result = unserialize(serialize($check)); + + assertCount(1, $result->getRunConditions()); + assertInstanceOf(Closure::class, $result->getRunConditions()[0]); + + assertMatchesObjectSnapshot($result); +}); diff --git a/tests/__snapshots__/QueueCheckTest__it_can_be_serialized__1.txt b/tests/__snapshots__/QueueCheckTest__it_can_be_serialized__1.txt new file mode 100644 index 00000000..fdf635ae --- /dev/null +++ b/tests/__snapshots__/QueueCheckTest__it_can_be_serialized__1.txt @@ -0,0 +1 @@ +O:38:"Spatie\Health\Checks\Checks\QueueCheck":8:{s:10:"expression";s:9:"* * * * *";s:4:"name";N;s:5:"label";N;s:9:"shouldRun";a:1:{i:0;O:47:"Laravel\SerializableClosure\SerializableClosure":1:{s:12:"serializable";O:46:"Laravel\SerializableClosure\Serializers\Native":5:{s:3:"use";a:0:{}s:8:"function";s:13:"fn() => false";s:5:"scope";s:29:"P\Tests\Checks\QueueCheckTest";s:4:"this";N;s:4:"self";s:32:"0000000000000000000000000000000000000000";}}}s:8:"cacheKey";s:37:"health:checks:queue:latestHeartbeatAt";s:14:"cacheStoreName";N;s:37:"failWhenTestJobTakesLongerThanMinutes";i:5;s:8:"onQueues";a:1:{i:0;s:4:"sync";}} \ No newline at end of file diff --git a/tests/__snapshots__/QueueCheckTest__it_can_be_unserialized__1.yml b/tests/__snapshots__/QueueCheckTest__it_can_be_unserialized__1.yml new file mode 100644 index 00000000..949b6eea --- /dev/null +++ b/tests/__snapshots__/QueueCheckTest__it_can_be_unserialized__1.yml @@ -0,0 +1,7 @@ +cacheStoreName: array +queues: + - sync +label: Queue +name: Queue +runConditions: + - { }