mirror of
https://github.com/amphp/parallel.git
synced 2025-01-17 20:58:36 +01:00
Only throw ContextException from receive, send, and join (#166)
This commit is contained in:
parent
5d975b640b
commit
815c2500bc
@ -16,8 +16,7 @@ interface Context extends Channel
|
||||
/**
|
||||
* @return TResult The data returned from the context.
|
||||
*
|
||||
* @throws ContextException If the context dies unexpectedly.
|
||||
* @throws ContextPanicError If the context throws an uncaught exception.
|
||||
* @throws ContextException If the context exited with an uncaught exception or non-zero code.
|
||||
*/
|
||||
public function join(?Cancellation $cancellation = null): mixed;
|
||||
}
|
||||
|
@ -36,34 +36,33 @@ abstract class AbstractContext implements Context
|
||||
} catch (ChannelException $exception) {
|
||||
try {
|
||||
$data = $this->join(new TimeoutCancellation(0.1));
|
||||
} catch (ContextException|ChannelException|CancelledException) {
|
||||
} catch (ChannelException|CancelledException) {
|
||||
if (!$this->isClosed()) {
|
||||
$this->close();
|
||||
}
|
||||
throw new ContextException(
|
||||
"The process stopped responding, potentially due to a fatal error or calling exit",
|
||||
0,
|
||||
$exception,
|
||||
"The context stopped responding, potentially due to a fatal error or calling exit",
|
||||
previous: $exception,
|
||||
);
|
||||
}
|
||||
|
||||
throw new \Error(\sprintf(
|
||||
'Process unexpectedly exited when waiting to receive data with result: %s',
|
||||
throw new ContextException(\sprintf(
|
||||
'Context unexpectedly exited when waiting to receive data with result: %s',
|
||||
flattenArgument($data),
|
||||
), 0, $exception);
|
||||
), previous: $exception);
|
||||
}
|
||||
|
||||
if (!$data instanceof ContextMessage) {
|
||||
if ($data instanceof ExitResult) {
|
||||
$data = $data->getResult();
|
||||
|
||||
throw new \Error(\sprintf(
|
||||
'Process unexpectedly exited when waiting to receive data with result: %s',
|
||||
throw new ContextException(\sprintf(
|
||||
'Context unexpectedly exited when waiting to receive data with result: %s',
|
||||
flattenArgument($data),
|
||||
));
|
||||
}
|
||||
|
||||
throw new \Error(\sprintf(
|
||||
throw new ContextException(\sprintf(
|
||||
'Unexpected data type from context: %s',
|
||||
flattenArgument($data),
|
||||
));
|
||||
@ -79,19 +78,19 @@ abstract class AbstractContext implements Context
|
||||
} catch (ChannelException $exception) {
|
||||
try {
|
||||
$data = $this->join(new TimeoutCancellation(0.1));
|
||||
} catch (ContextException|ChannelException|CancelledException) {
|
||||
} catch (ChannelException|CancelledException) {
|
||||
if (!$this->isClosed()) {
|
||||
$this->close();
|
||||
}
|
||||
|
||||
throw new ContextException(
|
||||
"The process stopped responding, potentially due to a fatal error or calling exit",
|
||||
0,
|
||||
$exception,
|
||||
"The context stopped responding, potentially due to a fatal error or calling exit",
|
||||
previous: $exception,
|
||||
);
|
||||
}
|
||||
|
||||
throw new \Error(\sprintf(
|
||||
'Process unexpectedly exited when sending data with result: %s',
|
||||
throw new ContextException(\sprintf(
|
||||
'Context unexpectedly exited when sending data with result: %s',
|
||||
flattenArgument($data),
|
||||
), 0, $exception);
|
||||
}
|
||||
@ -115,7 +114,7 @@ abstract class AbstractContext implements Context
|
||||
protected function receiveExitResult(?Cancellation $cancellation = null): ExitResult
|
||||
{
|
||||
if ($this->channel->isClosed()) {
|
||||
throw new ContextException("The context has already closed");
|
||||
throw new ContextException("The context has already closed without providing a result");
|
||||
}
|
||||
|
||||
try {
|
||||
@ -126,7 +125,7 @@ abstract class AbstractContext implements Context
|
||||
if (!$this->isClosed()) {
|
||||
$this->close();
|
||||
}
|
||||
throw new ContextException("Failed to receive result from context", 0, $exception);
|
||||
throw new ContextException("Failed to receive result from context", previous: $exception);
|
||||
}
|
||||
|
||||
if (!$data instanceof ExitResult) {
|
||||
@ -135,13 +134,13 @@ abstract class AbstractContext implements Context
|
||||
}
|
||||
|
||||
if ($data instanceof ContextMessage) {
|
||||
throw new \Error(\sprintf(
|
||||
"The context sent data instead of exiting: %s",
|
||||
flattenArgument($data),
|
||||
));
|
||||
$data = $data->getMessage();
|
||||
}
|
||||
|
||||
throw new \Error("Did not receive an exit result from context");
|
||||
throw new ContextException(\sprintf(
|
||||
"The context sent data instead of exiting: %s",
|
||||
flattenArgument($data),
|
||||
));
|
||||
}
|
||||
|
||||
$this->channel->close();
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace Amp\Parallel\Context\Internal;
|
||||
|
||||
use Amp\Parallel\Context\ContextException;
|
||||
use Amp\Parallel\Context\ContextPanicError;
|
||||
use function Amp\Parallel\Context\flattenThrowableBacktrace;
|
||||
|
||||
@ -42,11 +43,16 @@ final class ExitFailure implements ExitResult
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ContextPanicError
|
||||
* @throws ContextException
|
||||
*/
|
||||
public function getResult(): never
|
||||
{
|
||||
throw $this->createException();
|
||||
$exception = $this->createException();
|
||||
|
||||
throw new ContextException(
|
||||
'Process exited with an uncaught exception: ' . $exception->getMessage(),
|
||||
previous: $exception,
|
||||
);
|
||||
}
|
||||
|
||||
private function createException(): ContextPanicError
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Amp\Parallel\Context\Internal;
|
||||
|
||||
use Amp\Parallel\Context\ContextPanicError;
|
||||
use Amp\Parallel\Context\ContextException;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -13,7 +13,7 @@ interface ExitResult
|
||||
/**
|
||||
* @return TValue Return value of the callable given to the execution context.
|
||||
*
|
||||
* @throws ContextPanicError If the context exited with an uncaught exception.
|
||||
* @throws ContextException If the context exited with an uncaught exception.
|
||||
*/
|
||||
public function getResult(): mixed;
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ namespace Amp\Parallel\Test\Context;
|
||||
use Amp\CancelledException;
|
||||
use Amp\Parallel\Context\Context;
|
||||
use Amp\Parallel\Context\ContextException;
|
||||
use Amp\Parallel\Context\ContextPanicError;
|
||||
use Amp\PHPUnit\AsyncTestCase;
|
||||
use Amp\TimeoutCancellation;
|
||||
use function Amp\async;
|
||||
@ -26,7 +25,7 @@ abstract class AbstractContextTest extends AsyncTestCase
|
||||
|
||||
public function testFailingProcess(): void
|
||||
{
|
||||
$this->expectException(ContextPanicError::class);
|
||||
$this->expectException(ContextException::class);
|
||||
$this->expectExceptionMessage('No string provided');
|
||||
|
||||
$context = $this->createContext(__DIR__ . "/Fixtures/test-process.php");
|
||||
@ -35,40 +34,33 @@ abstract class AbstractContextTest extends AsyncTestCase
|
||||
|
||||
public function testThrowingProcessOnReceive(): void
|
||||
{
|
||||
$this->expectException(ContextPanicError::class);
|
||||
$this->expectException(ContextException::class);
|
||||
$this->expectExceptionMessage('Test message');
|
||||
|
||||
$context = $this->createContext(__DIR__ . "/Fixtures/throwing-process.php");
|
||||
|
||||
$cancellation = new TimeoutCancellation(0.1);
|
||||
|
||||
try {
|
||||
$context->receive($cancellation);
|
||||
self::fail('Receiving should have failed');
|
||||
} catch (ContextException) {
|
||||
$context->join($cancellation);
|
||||
}
|
||||
$context->receive($cancellation);
|
||||
|
||||
self::fail('Receiving should have failed');
|
||||
}
|
||||
|
||||
public function testThrowingProcessOnSend(): void
|
||||
{
|
||||
$this->expectException(ContextPanicError::class);
|
||||
$this->expectExceptionMessage('Test message');
|
||||
$this->expectException(ContextException::class);
|
||||
|
||||
$context = $this->createContext(__DIR__ . "/Fixtures/throwing-process.php");
|
||||
delay(1);
|
||||
delay(1); // Give process time to start.
|
||||
|
||||
try {
|
||||
$context->send(1);
|
||||
self::fail('Sending should have failed');
|
||||
} catch (ContextException) {
|
||||
$context->join(new TimeoutCancellation(1));
|
||||
}
|
||||
$context->send(1);
|
||||
|
||||
self::fail('Sending should have failed');
|
||||
}
|
||||
|
||||
public function testInvalidScriptPath(): void
|
||||
{
|
||||
$this->expectException(ContextPanicError::class);
|
||||
$this->expectException(ContextException::class);
|
||||
$this->expectExceptionMessage("No script found at '../test-process.php'");
|
||||
|
||||
$context = $this->createContext("../test-process.php");
|
||||
@ -77,7 +69,7 @@ abstract class AbstractContextTest extends AsyncTestCase
|
||||
|
||||
public function testInvalidResult(): void
|
||||
{
|
||||
$this->expectException(ContextPanicError::class);
|
||||
$this->expectException(ContextException::class);
|
||||
$this->expectExceptionMessage('The given data could not be serialized');
|
||||
|
||||
$context = $this->createContext(__DIR__ . "/Fixtures/invalid-result-process.php");
|
||||
@ -86,7 +78,7 @@ abstract class AbstractContextTest extends AsyncTestCase
|
||||
|
||||
public function testNoCallbackReturned(): void
|
||||
{
|
||||
$this->expectException(ContextPanicError::class);
|
||||
$this->expectException(ContextException::class);
|
||||
$this->expectExceptionMessage('did not return a callable function');
|
||||
|
||||
$context = $this->createContext(__DIR__ . "/Fixtures/no-callback-process.php");
|
||||
@ -95,7 +87,7 @@ abstract class AbstractContextTest extends AsyncTestCase
|
||||
|
||||
public function testParseError(): void
|
||||
{
|
||||
$this->expectException(ContextPanicError::class);
|
||||
$this->expectException(ContextException::class);
|
||||
$this->expectExceptionMessage('contains a parse error');
|
||||
|
||||
$context = $this->createContext(__DIR__ . "/Fixtures/parse-error-process.inc");
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Amp\Parallel\Test\Context\Internal;
|
||||
|
||||
use Amp\Parallel\Context\ContextPanicError;
|
||||
use Amp\Parallel\Context\ContextException;
|
||||
use Amp\Parallel\Context\Internal\ExitFailure;
|
||||
use Amp\PHPUnit\AsyncTestCase;
|
||||
|
||||
@ -15,7 +15,7 @@ class ExitFailureTest extends AsyncTestCase
|
||||
$result = new ExitFailure($exception);
|
||||
try {
|
||||
$result->getResult();
|
||||
} catch (ContextPanicError $caught) {
|
||||
} catch (ContextException $caught) {
|
||||
self::assertGreaterThan(0, \stripos($caught->getMessage(), $message));
|
||||
return;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user