await가 기다리는 시간 제한하기
작업이 주어진 시간보다 오래 걸리지 않는다는 보장이 필요한 경우가 많습니다. 예를 들어 UserDirectory가 너무 오랫동안 응답하지 않으면 API가 고장 난 것처럼 느껴질 수 있습니다. 여기에는 두 가지 가능한 해법이 있습니다.
file_get_contents작업 수준에서 타임아웃을 설정하고 함수의 코드를 변경합니다.await에 직접 제한을 추가합니다.
use function Async\timeout;
use Async\OperationCanceledException;
try {
$isValid = await($validation, timeout(2000));
} catch (OperationCanceledException $e) {
$validation->cancel();
} catch (RemoteApiException $e) {
}await를 제한하면 좋은 점은 validateToken의 코드를 변경할 필요가 없다는 것입니다. 동시에, 예상할 법한 catch (TimeoutException $e)가 아니라 catch (OperationCanceledException $e)라는 점에 주목하세요.
OperationCanceledException
timeout()은 그 자체로는 아무것도 던지지 않습니다. 취소 토큰인 Async\Timeout 객체를 반환할 뿐입니다. 아래 코드는 스크립트가 아무리 오래 돌아도 결코 예외를 던지지 않습니다:
use function Async\timeout;
$token = timeout(2000); // just an object; nothing happensThe token only takes effect once it is handed to an operation as a cancellation argument:
use function Async\timeout;
use Async\OperationCanceledException;
try {
$isValid = await($validation, timeout(2000));
} catch (OperationCanceledException $e) {
$validation->cancel();
echo $e->getPrevious()->getMessage(); // TimeoutException의 메시지
}토큰이 작동하면 TimeoutException이 아니라 OperationCanceledException이 옵니다. 타임아웃 자체는 그 안의 getPrevious()에 들어 있습니다. 이는 의도된 것으로, await에 대한 try-catch 처리 로직을 단순화하고 취소된 대기와 코루틴 내부에서 발생한 예외를 명확히 구분하기 위한 것입니다. 코루틴은 일반적으로 스스로 OperationCanceledException을 던지면 안 됩니다.
await 대기를 제한하는 데 사용하는 것이 반드시 timeout()일 필요는 없습니다. 다른 어떤 코루틴이 될 수도 있고, 임의의 작업 완료를 나타내는 논리적 계약인 Future가 될 수도 있습니다.