1
0
mirror of https://github.com/danog/parallel.git synced 2024-11-26 20:34:40 +01:00

Improve error messages when unserializable data is used

This commit is contained in:
Aaron Piotrowski 2018-10-23 22:10:12 -05:00
parent 3c0baa4e43
commit 14def89bff
No known key found for this signature in database
GPG Key ID: ADD1EF783EDE9EEB
6 changed files with 86 additions and 2 deletions

View File

@ -2,6 +2,8 @@
namespace Amp\Parallel\Worker\Internal;
use Amp\Failure;
use Amp\Parallel\Worker\Task;
use Amp\Promise;
use Amp\Success;
@ -19,6 +21,13 @@ final class TaskSuccess extends TaskResult
public function promise(): Promise
{
if ($this->result instanceof \__PHP_Incomplete_Class) {
return new Failure(new \Error(\sprintf(
"Class instances returned from %s::run() must be autoloadable by the Composer autoloader",
Task::class
)));
}
return new Success($this->result);
}
}

View File

@ -4,6 +4,7 @@ namespace Amp\Parallel\Worker;
use Amp\Coroutine;
use Amp\Parallel\Sync\Channel;
use Amp\Parallel\Sync\SerializationException;
use Amp\Promise;
use function Amp\call;
@ -50,7 +51,12 @@ final class TaskRunner
$job = null; // Free memory from last job.
yield $this->channel->send($result);
try {
yield $this->channel->send($result);
} catch (SerializationException $exception) {
// Could not serialize task result.
yield $this->channel->send(new Internal\TaskFailure($result->getId(), $exception));
}
$result = null; // Free memory from last result.

View File

@ -7,6 +7,7 @@ use Amp\Parallel\Sync\SerializationException;
use Amp\Parallel\Worker\Environment;
use Amp\Parallel\Worker\Task;
use Amp\Parallel\Worker\TaskError;
use Amp\Parallel\Worker\TaskException;
use Amp\Parallel\Worker\WorkerException;
use Amp\PHPUnit\TestCase;
@ -203,7 +204,7 @@ abstract class AbstractWorkerTest extends TestCase
{
}
});
$this->fail("Tasks that cannot be autoloaded should throw an exception");
$this->fail("Tasks that cannot be serialized should throw an exception");
} catch (SerializationException $exception) {
$this->assertSame(0, \strpos($exception->getMessage(), "The given data cannot be sent because it is not serializable"));
}
@ -212,6 +213,38 @@ abstract class AbstractWorkerTest extends TestCase
});
}
public function testUnserializableResult()
{
Loop::run(function () {
$worker = $this->createWorker();
try {
yield $worker->enqueue(new UnserializableResultTask);
$this->fail("Tasks results that cannot be serialized should throw an exception");
} catch (TaskException $exception) {
$this->assertSame(0, \strpos($exception->getMessage(), "Uncaught Amp\Parallel\Sync\SerializationException in worker"));
}
yield $worker->shutdown();
});
}
public function testNonAutoloadableResult()
{
Loop::run(function () {
$worker = $this->createWorker();
try {
yield $worker->enqueue(new NonAutoloadableResultTask);
$this->fail("Tasks results that cannot be autoloaded should throw an exception");
} catch (\Error $exception) {
$this->assertSame(0, \strpos($exception->getMessage(), "Class instances returned from Amp\Parallel\Worker\Task::run() must be autoloadable by the Composer autoloader"));
}
yield $worker->shutdown();
});
}
public function testUnserializableTaskFollowedByValidTask()
{
Loop::run(function () {

View File

@ -0,0 +1,15 @@
<?php
namespace Amp\Parallel\Test\Worker;
use Amp\Parallel\Worker\Environment;
use Amp\Parallel\Worker\Task;
class NonAutoloadableResultTask implements Task
{
public function run(Environment $environment)
{
require __DIR__ . "/non-autoloadable-class.php";
return new NonAutoloadableClass;
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace Amp\Parallel\Test\Worker;
use Amp\Parallel\Worker\Environment;
use Amp\Parallel\Worker\Task;
class UnserializableResultTask implements Task
{
public function run(Environment $environment)
{
return function () {}; // Anonymous functions are not serializable.
}
}

View File

@ -0,0 +1,7 @@
<?php
namespace Amp\Parallel\Test\Worker;
class NonAutoloadableClass
{
}