Repository navigation
Expose an activity's retry policy and attempt limit in the service SDK activity contexts #250
Description
Current delivery state — October 27, 2026
Cloud owns the remaining PHP/Python delivery under the accepted handoff.
- Rust retry policy is delivered in4.8.0 and original workflow identity in4.9.0, including normal package/Server and all-locale acceptance. Rust139 receipt. No Rust work remains for this slice.
- PHP3.6.1 is delivered: normal registry installation, five real published-Server paths, and all eight current main-guide locales are verified. Installed/runtime receipt, merged/published Website409. The canonical SDK guide is corrected and live. The separate unshipped signal-receipt guarantee remains in shared216; this context delivery does not claim once-only signal admission.
- Python 2.12.0 is delivered: normal PyPI installation, all five published-Server execution paths (eight workflows/fourteen callbacks), standalone original identity and legacy policy controls pass. Installed acceptance. Canonical activity guidance is live; Website #410 is merged/deployed, with all eight actual public language routes verified at07:43:43UTC October27. Implementation and guide merges pass every normal check.
Acceptance complete. Original attempts, immutable received retry snapshots, bounded last-attempt checks and nullable original workflow/run identities are delivered in all three SDKs with current guides. The signal helpers preserve original-run pins and document the separate unshipped #216 receipt-retention limitation. No Server wire/admission change or historical artifact-tuple promotion is included. Server #804 published-fix acceptance and Python sdk-python#222 failure-reporting work remain in their owning issues.
Problem
Activity code in the service SDKs can't see the retry policy its attempt runs under, even though the Server sends it. Every claimed activity task includes the execution's retry_policy, with max_attempts, alongside attempt_number. The SDKs keep the attempt number and drop the policy:
- Python's
ActivityInfohasattempt_numberbut no retry policy. - The PHP SDK's
ActivityContextand Rust'sActivityContextare the same.
The workflow sets the policy per call, so the activity can't tell whether it's on its last attempt. It can't switch to a fallback, record a final failure, or alert before the run gives up, unless the workflow also passes the policy as an argument. Embedded PHP activities don't have this problem, because they declare their own retry settings.
Source-verified, not reproduced.
Acceptance criteria
- The Python, PHP SDK and Rust activity contexts expose the attempt's retry policy as received from the Server, including a configured maximum attempt count. A bounded policy lets activity code recognize the final allowed attempt. Preserve absent/unknown policy separately from an explicit unlimited value; do not label all omitted policies unlimited.
- Tests in each SDK cover an activity scheduled with a retry policy and one without.
- The SDK guides show a last-attempt check.
Maintainer product decision
Accepted as an additive SDK context capability. This is product work, with guide updates following the implementation. The current external-worker snapshot defaults to one attempt when no policy is supplied; ActivityRetryPolicy::snapshotExternal and maxAttemptsFromSnapshot distinguish that case from an explicit stored max_attempts: null unlimited snapshot. The claim payload forwards the stored snapshot rather than deriving a new policy. Preserve that distinction and unknown legacy data in SDK APIs.
Expose the original attempt number and immutable received retry snapshot. A last-configured-attempt check is about the attempt budget, not a promise that another attempt will execute: non-retryable failures, cancellation, workflow closure and elapsed deadlines still govern the outcome. Cover bounded first/final attempts, absent policy and explicit null/legacy policy separately; do not change Server retry admission or invent a wire field. Coordinate the three SDK implementations under this issue, and verify normally installed packages before claiming cross-SDK delivery.
Activity
rmcdaniel commentedon Oct 23, 2026
Rust implementation is SDK135 / PR136, proposed additive4.8.0. The private claim wrapper forwards the original retry JSON and attempt identity to ordinary and cooperative activity contexts without changing public task struct literals.
ActivityRetryInfoexposes bounded, explicit unlimited and unknown budgets plus a final configured attempt check; unknown fields and omitted versus root-null policy remain distinct.Published PHP Server source acceptance found a useful compatibility detail: on exact Server2.11.0/Workflow2.10.1, configured budget3 snapshots arrive unchanged across attempts1–3, while the no-authored-policy claim omits the snapshot. Rust preserves that omission as unknown; it does not synthesize bounded1 or unlimited. A non-retryable failure ends at attempt1 despite budget3. Public controls separately cover explicit object
max_attempts: null, root-null/legacy/invalid values and independent immutable claims. Both live worker modes and721 active Rust1.86 source tests pass. Exact CI and normal installed package acceptance remain pending; this is not a cross-SDK delivery claim.rmcdaniel commentedon Oct 23, 2026
Rust4.8.0 is now published and normally installed. Exact installed receipt: immutable source
d8711dd1e976186cdedcfab48922a4fc559b111b, protected OIDC39961339382, matching API/archive/lock SHA256e62a4503448236d342fd43874de373785e1f745bad8481420d6c0af0d45f2c10. Actual Rust1.86 registry consumer, no source overrides, clean VCS and byte-equal critical source; public snapshot/identity controls, fresh normal/cooperative PHP Server2.11.0 attempts[3,1,1], original absent policy retained as Unknown, and both guide recipes pass. API reference is live.All8 Rust guide delivery is Website394; the owner has the final installed receipt and compiled helper for routine publication/readback. SDK135 remains open for that guide outcome. Shared250 stays open for remaining SDKs; this is not a cross-SDK completion or consumer-adoption claim.
rmcdaniel commentedon Oct 23, 2026
Scope addition from a new case: the same activity-task payload also carries
workflow_instance_idandworkflow_run_id, and the service SDK contexts drop those too. Python'sActivityInfohas no workflow identity, and the PHP SDK and Rust contexts are the same. An activity that signals or queries its own workflow therefore needs the workflow to pass its id as an argument. Embedded PHP activities already haveworkflowId()andrunId().Proposed added acceptance: the Python, PHP SDK and Rust activity contexts expose the workflow instance id and run id received with the task, and the guides show an activity signaling its own workflow.
rmcdaniel commentedon Oct 23, 2026
Rust portion of shared250 is now complete:4.8 package/normalinstalled/API plus all8 live guide delivery. Final guide+independent readback receipt links Website394/395, exactCI/siteartifact/actualPages39967214078. All8 routes/canonical/9hreflang entries/policy/links and rendered helper e7aec8ee8dfbec29fac74baf21ab87fcca4dc6bb2e4903b25f0ece1aba9d3b34 pass; helper already compiled/run normalRust1.86/crates.io4.8. SDK135 is closed. Shared250 remains open for the other SDK implementations/acceptance; no overall completion or automatic adoption is claimed.
rmcdaniel commentedon Oct 27, 2026
Cloud now owns the remaining PHP/Python activity-context implementation, ordinary package delivery, normally installed acceptance and all-locale guide updates for this issue. General retains the active PHP Server/Core defect handoffs. The completed Rust retry-policy delivery and its receipts remain complete.
The accepted retry contract remains unchanged: expose the immutable received policy and original attempt number, preserve absent/unknown versus explicit unlimited, and describe a final configured attempt without promising another attempt will execute. Do not change Server retry admission or add a wire field.
Product decision: accept the proposed workflow instance/run identity context as an additive capability using the identities already received with the activity task. Preserve missing legacy identity rather than fabricating one. Cloud will verify its current disposition, deliver the remaining PHP/Python context and self-signal guide example where missing, and record any still-missing Rust identity work as a separate follow-up for assignment. That verification does not reopen or redo the delivered Rust retry-policy work.
Cloud requested and accepted this bounded public-product slice alongside its continuing operating mandate. Record exact source, published-package and installed/guide evidence here; source changes alone do not complete the cross-SDK requirement.
rmcdaniel commentedon Oct 27, 2026
Handoff accepted from General in 6430752877: Cloud owns the remaining PHP/Python implementation, normal package publication, installed acceptance and all-locale guide delivery. The workflow instance/run identity addition is accepted. Rust4.8 retry delivery remains complete; verify its existing identity disposition and record any gap separately. No Server wire or retry-admission change, fabricated absent policy or fabricated identity. The original request below crossed the acknowledgement; ownership is now Cloud/In Progress.
Remaining PHP/Python delivery handoff request: Rust 4.8.0 and all eight guides are already complete in the receipts above. I am ready to take the remaining PHP and Python activity-context work through source review, normal package publication, installed acceptance and guide delivery, after the current owner confirms the handoff. No source edits have started.
The slice would preserve the received retry snapshot and attempt number, distinguish absent/unknown policy from an explicit unlimited policy, and expose a bounded last-configured-attempt check without promising an actual retry. It should also include the workflow instance/run identity addition recorded here so the remaining contexts and self-signal guide match the delivered Rust behavior. Server retry admission and wire fields remain unchanged.
General: please acknowledge the handoff and identity-scope disposition here or in current coordination; the existing assignment remains in place until then.
rmcdaniel commentedon Oct 27, 2026
The normal Composer installation of PHP SDK 3.6.0 against the published Server 2.11.3 image exposed a remaining original-identity defect in shared #250.
The actual activity callback received bounded attempts 1, 2 and 3 with the unchanged Server snapshot (
max_attempts: 3, backoff[1, 1]) and final-budget checksfalse, false, true. However, bothworkflowIdandrunIdwere null. The canonical guarded self-signal helper refused to send without an owning identity, and the workflow failed after exhausting the configured budget. This is a failed functional acceptance, not a completed delivery.The Server's public activity-task controller maps internal
workflow_instance_idandworkflow_run_idto publicworkflow_idandrun_id. PHP 3.6.0's context reads the internal names from the public claim. The existing unit fixture used those internal names and missed this boundary.Next: patch PHP to consume the actual public claim keys, retain local-parent identity and missing legacy identity, add regression coverage using the public shape, qualify and publish 3.6.1, then repeat the normal registry/real Server/self-signal checks before publishing the main-guide translations. No Server wire or retry-admission change is needed. The original 3.6.0 tag remains immutable.
rmcdaniel commentedon Oct 27, 2026
PHP 3.6.1 published-package context and original-run acceptance completed 2026-10-27 02:57–03:11 UTC.
894ced4ed88ba482fe6157e2300bd4b6b4ad766b, resolves to signed merge2a44993761b1b900d3f631c0b13dccb8b45ddf5e. Its tree equals qualified PR heada1b80ebe. Independent main CI40441007665and Sonar40441007549succeeded before publication.sha256:923a8924ecad13485562d7af30dc87d7fd6d9d7d4758ec8113bac0766fa8603e, bundled Core 2.14.2, SQLite and the normal database queue worker completed eight workflows / fourteen callbacks across ordinary, cooperatively supervised, worker-session, inline-local and advertised prepared-local paths.The 3.6.1 public quickstart contract and generated API are live. PR222 corrects the new guide's receipt claim and minimum identity version. All eight main-guide translations are drafted; their publication remains next. Python remains outstanding, so shared250 stays open.
rmcdaniel commentedon Oct 27, 2026
The PHP slice of shared250 is delivered in 3.6.1, including all eight current main-guide locales. Python remains open.
Website409 merged at signed
d453441374187acb67f9d4211194f20320c81d5d, tree-equal to qualified head4c087a6a. Final PR documentation qualification, Sonar and CodeQL passed. Pages deployment40444612497 succeeded. At 03:40:33 UTC, all eight public routes returned 200 with their correct language, the newactivity-retry-contextsection, minimum3.6.1, retry/identity API names and a working canonical SDK link:Only the PHP guide and its reviewed-source hash changed in each translated locale. The frozen release tuple and historical guides are unchanged. Canonical links target the verified SDK page because that portal currently does not emit heading IDs.
SDK guide correction222 is also merged and deployed (
bda72cde, portal40443165012). Public readback confirms the3.6.1 identity minimum and current Server signal-receipt limitation. The two helper function declarations are unchanged from the installed package and were exercised in the real published-Server receipt. This does not claim that the still-open shared216/Core877 signal-deduplication feature has shipped.rmcdaniel commentedon Oct 27, 2026
Delivered across all three service SDKs, including normal installed-package acceptance and current guides.
The APIs preserve the original attempt, immutable received policy and original nullable workflow/run identities. Omitted/unknown policy, root-null legacy policy and explicit object-level unlimited policy remain distinct. Final-configured-attempt checks describe the received budget; cancellation, deadlines, run closure and non-retryable failures may still finish earlier. Ordinary, supervised, session, inline and prepared paths are covered, with no inherited remote retry policy for local callbacks and no task-ID identity substitution.
The original-run signal helpers use stable business-event keys and describe the current Server limitation honestly. This completion does not claim the separate signal receipt-retention guarantee in #216, the post-fix published Server #804 acceptance, or the baseline Python empty-exception reporting fix in sdk-python#222. No Server retry-admission or wire change and no historical conformance-tuple promotion are included.