Outcome
Status、Outcome、404/410とPHP Query契約を必要な時に引く。
正常完了したDeferred Operationは、Operation IDごとに型付きOutcomeを保存します。Browserや外部ConsumerはPublic Status Resource、Generated Clientは.status()/.wait()を主経路にします。PHP Adapterから読む場合も、Default-deny OperationOutcomeQueryへCurrent Actor、Current Tenant、OperationDataPurposeを渡します。Raw Reader、Persistence Payload、PostgreSQLのSchema Versionへ直接依存しないでください。
const current = await GenerateReport.status(operationId, options);
if (current.ok && current.kind === 'completed') {
current.data.outcome.reportName;
current.data.outcome.operationId;
}
Status Resultはaccepted/running/retry_scheduledをPending、completed/rejected/failed/dead_letteredをTerminalとして区別します。認可済みでRetention期限切れを証明できる場合は410 expired、UnknownとDenyは同じ404 operation_unavailableです。
認可済みPHP QueryからOutcomeを読む
use BlackOps\Core\ActorRef;
use BlackOps\Core\Identifier\OperationId;
use BlackOps\Core\TenantRef;
use BlackOps\OperationData\OperationDataPurpose;
use BlackOps\OperationData\OperationOutcomeFound;
use BlackOps\OperationData\OperationOutcomeQuery;
function reportResult(
OperationOutcomeQuery $outcomes,
string $operationId,
?ActorRef $currentActor,
?TenantRef $currentTenant,
): ?ReportGenerated
{
$result = $outcomes->find(
OperationId::fromString($operationId),
$currentActor,
$currentTenant,
OperationDataPurpose::fromString('report.read'),
);
if (!$result instanceof OperationOutcomeFound) {
return null;
}
$outcome = $result->record()->outcome();
return $outcome instanceof ReportGenerated ? $outcome : null;
}
OperationOutcomeFoundはOutcomeRecordを返し、OperationOutcomeUnavailableはUnknown、Tenant不一致、Deny、Retention削除を安全に表します。Allow前にProtected BlobをDecodeしません。
nullの意味を区別する
nullだけでは次を区別できません。
- Operation IDが未知である
- Operationがまだ完了していない
- OperationがRejected/Failed/Dead Letterになった
- Outcomeの独立した保持期限を過ぎた
Public Status Query/HTTP Resourceはこれらを区別します。OperationOutcomeQuery::find()のUnavailableをStatus判定へ流用しません。FrameworkのInfrastructure SPI、Table、Payload形式を利用者向けContractにしないでください。判定例はOutcome Statusを確認してください。
保存するOutcome
DeferredのCompletedだけがOutcome Recordを作ります。Inline completedはHTTP ResponseだけへOutcomeを返し、Outcome Recordを作りません。Rejected、Failed、Retry Scheduled、Dead Letter、Claim Lost、Grace Timeoutは成功Outcomeを作りません。値のないDeferred成功を表すEmptyOutcomeも型付きOutcomeとして保存します。
EphemeralOutcomeは例外です。HTTPへ一度だけ返すCredential ResponseなのでOutcome Rowを作らず、認可済みStatus Queryにもoperation_unavailableを返します。Journal上のEmptyOutcomeをDeclared Ephemeral Classへ復元しないでください。
PostgreSQL Storeは最初の完了結果を上書きせず、重複Saveを拒否します。未対応Schema Version、破損Payload、保存型の不一致、Outcomeを実装しない値はOutcomeStoreExceptionになります。
Retention
OutcomeのRetentionはTransport Payload、Journal、Dead Letterから独立しています。RetentionPolicy::outcomeRetention()はOutcomeRecord::completedAt()を基準に期限を判定します。ActiveなOperation Holdがある場合、PlannerとPurgeはOutcomeを対象外にします。
Purgeが成功すると、同じDatabase TransactionでPayloadを含まない監査Recordを保存し、RetentionPurgeResult::outcomesDeleted()へ削除件数を加算します。保持期間とHoldの運用はRetentionを確認してください。
次にLifecycleの結果を整理する
Status、Outcome、Expiredの差をLifecycle全体で理解する場合は、Lifecycleへ戻ります。