diff --git a/composer.json b/composer.json index 8556574f..4db301fb 100644 --- a/composer.json +++ b/composer.json @@ -93,7 +93,7 @@ } }, "durable-workflow": { - "product-train": "3.6.0", + "product-train": "3.6.1", "supported-server-versions": "2.5.0", "worker-protocol-version": "1.20", "control-plane-version": "2", diff --git a/docs/quickstart-contract.json b/docs/quickstart-contract.json index 0db217f2..5709b6b5 100644 --- a/docs/quickstart-contract.json +++ b/docs/quickstart-contract.json @@ -3,8 +3,8 @@ "schema_version": 2, "package": { "name": "durable-workflow/sdk", - "published_version": "3.6.0", - "composer_requirement": "3.6.0", + "published_version": "3.6.1", + "composer_requirement": "3.6.1", "onboarding_requirement": "^3.6" }, "runtime_targets": { diff --git a/src/Worker/ActivityContext.php b/src/Worker/ActivityContext.php index 7bb2aeed..ca0471b8 100644 --- a/src/Worker/ActivityContext.php +++ b/src/Worker/ActivityContext.php @@ -12,9 +12,9 @@ final class ActivityContext { public readonly ActivityRetryInfo $retryInfo; - /** Owning workflow_instance_id from the claim, or known parent local task. */ + /** Original workflow_id from the public claim, or known parent local task. */ public readonly ?string $workflowId; - /** Original owning workflow_run_id; unavailable legacy identity stays null. */ + /** Original run_id from the public claim; unavailable legacy identity stays null. */ public readonly ?string $runId; /** @@ -33,8 +33,12 @@ public function __construct( array $taskMetadata = [], ) { $this->retryInfo = ActivityRetryInfo::fromTask($attemptNumber, $taskMetadata); - $this->workflowId = self::receivedIdentity($taskMetadata['workflow_instance_id'] ?? null); - $this->runId = self::receivedIdentity($taskMetadata['workflow_run_id'] ?? null); + // Public claim keys take precedence, including explicit null. Retain the + // internal-name aliases used by local parents and 3.6.0 constructor callers. + $this->workflowId = self::receivedIdentity(array_key_exists('workflow_id', $taskMetadata) + ? $taskMetadata['workflow_id'] : ($taskMetadata['workflow_instance_id'] ?? null)); + $this->runId = self::receivedIdentity(array_key_exists('run_id', $taskMetadata) + ? $taskMetadata['run_id'] : ($taskMetadata['workflow_run_id'] ?? null)); } private static function receivedIdentity(mixed $value): ?string diff --git a/tests/ActivityRetryInfoTest.php b/tests/ActivityRetryInfoTest.php index f5ca185d..1fa67ac3 100644 --- a/tests/ActivityRetryInfoTest.php +++ b/tests/ActivityRetryInfoTest.php @@ -69,6 +69,29 @@ public function testLegacyConstructorAndServerFreeActivitiesHaveUnknownMetadata( self::assertNull($context->runId); } + public static function originalIdentities(): array + { + return [ + 'public claim' => [['workflow_id' => '0', 'run_id' => '017'], '0', '017'], + 'legacy aliases' => [['workflow_instance_id' => 'parent', 'workflow_run_id' => 'parent-run'], 'parent', 'parent-run'], + 'public takes precedence' => [['workflow_id' => 'original', 'run_id' => 'original-run', + 'workflow_instance_id' => 'other', 'workflow_run_id' => 'other-run'], 'original', 'original-run'], + 'public null remains unknown' => [['workflow_id' => null, 'run_id' => null, + 'workflow_instance_id' => 'other', 'workflow_run_id' => 'other-run'], null, null], + 'invalid identity remains unknown' => [['workflow_id' => 42, 'run_id' => ''], null, null], + 'partially missing identity' => [['workflow_id' => 'original'], 'original', null], + ]; + } + + #[DataProvider('originalIdentities')] + public function testOriginalIdentityUsesThePublicClaimWithoutRetargeting(array $metadata, ?string $workflowId, ?string $runId): void + { + $context = new ActivityContext(new Client('https://server.example'), 'task', 'attempt', 'owner', 'activity', 1, + taskMetadata: $metadata); + self::assertSame($workflowId, $context->workflowId); + self::assertSame($runId, $context->runId); + } + public function testInlineLocalActivityRetainsParentIdentityWithoutInventingRetryPolicy(): void { $completion = null; @@ -114,7 +137,7 @@ public static function claimedMetadata(): array { return [ 'bounded' => [['retry_policy' => ['max_attempts' => 3, 'future' => [true, null]], 'attempt_number' => 3, - 'workflow_instance_id' => '0', 'workflow_run_id' => '017'], true, true], + 'workflow_id' => '0', 'run_id' => '017'], true, true], 'absent legacy' => [[], false, null], 'explicit root null' => [['retry_policy' => null], true, null], 'unlimited' => [['retry_policy' => ['max_attempts' => null]], true, false], @@ -158,7 +181,7 @@ public function testOrdinaryWorkerExposesTheReceivedClaim(array $metadata, bool self::assertSame($provided, $result['provided']); self::assertSame($metadata['retry_policy'] ?? null, $result['policy']); self::assertSame($last, $result['last']); - self::assertSame($metadata['workflow_instance_id'] ?? null, $result['workflow_id']); - self::assertSame($metadata['workflow_run_id'] ?? null, $result['run_id']); + self::assertSame($metadata['workflow_id'] ?? null, $result['workflow_id']); + self::assertSame($metadata['run_id'] ?? null, $result['run_id']); } } diff --git a/tests/CooperativeRemoteActivityTest.php b/tests/CooperativeRemoteActivityTest.php index a01dc41d..aaa9a698 100644 --- a/tests/CooperativeRemoteActivityTest.php +++ b/tests/CooperativeRemoteActivityTest.php @@ -295,7 +295,7 @@ public function testUserProgressIsProxiedAndResultTypesSurvive(): void public function testReceivedRetryAndWorkflowIdentityReachTheSupervisedCallback(): void { foreach ([[], ['attempt_number' => 3, 'retry_policy' => ['max_attempts' => 3, 'future' => [true]], - 'workflow_instance_id' => 'workflow', 'workflow_run_id' => 'original-run']] as $metadata) { + 'workflow_id' => 'workflow', 'run_id' => 'original-run']] as $metadata) { $transport = new RemoteOwnerTransport(); $transport->taskMetadata = $metadata; $pids = []; @@ -316,8 +316,8 @@ public function testReceivedRetryAndWorkflowIdentityReachTheSupervisedCallback() self::assertSame($metadata['retry_policy'] ?? null, $result['policy']); self::assertSame($metadata !== [], $result['provided']); self::assertSame($metadata === [] ? null : true, $result['last']); - self::assertSame($metadata['workflow_instance_id'] ?? null, $result['workflow_id']); - self::assertSame($metadata['workflow_run_id'] ?? null, $result['run_id']); + self::assertSame($metadata['workflow_id'] ?? null, $result['workflow_id']); + self::assertSame($metadata['run_id'] ?? null, $result['run_id']); } }