Skip to content

Add capped exponential activity retry authoring - #328

Merged
rmcdaniel merged 3 commits into
mainfrom
sdk-python/219-generated-backoff-cap
Nov 14, 2026
Merged

rmcdaniel merged 3 commits into
mainfrom
sdk-python/219-generated-backoff-cap

Conversation

@rmcdaniel

Copy link
Copy Markdown
Member

New Python generated activity policies have no default maximum today, so 20 attempts can schedule a final delay of 262,144 seconds. Add the accepted ActivityRetryPolicy.exponential(...) authoring path with a finite 60-second default maximum, using the existing durable command shape. This implements the remaining Python cap source slice of shared #219.

Nine total attempts now generate 1, 2, 4, 8, 16, 32, 60, 60 through the factory. Explicit finite non-negative maxima retain existing cap-before-ceiling resolution, including fractional seconds and zero. The factory rejects None, nonfinite values and invalid generated parameters. Total-attempt and schedule-to-close semantics stay intact. The legacy constructor, its omitted/explicit-None maximum, explicit lists, and recorded schedules retain their values. New examples recommend the factory and the guide states exactly which path selects the default.

Validation: 310 focused policy/replay/local-executor and official corpus checks pass, with candidate source origin explicitly verified. Ruff, mypy and corpus-policy validation pass. Three frozen command JSON strings were captured from the approved published 2.17.2 registry package; current legacy authoring must match their bytes. Controlled retained local histories replay their original policies/attempts with a callback that fails if invoked. Local executor cap checks intercept sleep and prove selected delays, not elapsed timing or installed acceptance.

This is an additive API change, with no new Server role, wire field or prepared-local carrier. Source review, all normal checks, candidate artifact review, published-package installed proof and stable/root documentation follow-through remain required before delivery is claimed. No release or installed runtime has been selected. The unrelated #980 physical-row requirement remains held.

@sonarqubecloud

Copy link
Copy Markdown

@rmcdaniel

Copy link
Copy Markdown
Member Author

Security source/API PASS for exact 6c94f6a152ec5434c607b427a36b5af855403a70 / tree ae5f66480b2d3c39d424b115cab989c981d1a226.

The new ActivityRetryPolicy.exponential(...) boundary is additive and keeps the durable command shape unchanged. It validates a positive integer total-attempt count and finite, non-boolean numeric initial/coefficient/maximum values; coefficient remains at least one and the maximum is finite and non-negative. The factory's 60-second default produces the documented eight delays for nine total attempts, copies the caller's non-retryable list, and delegates cap-before-ceiling command resolution to the existing implementation.

The legacy constructor and its None/omitted maximum, explicit backoff lists, to_dict() wire fields and replay paths are byte-unchanged. The frozen 2.17.2 command cases still match exact canonical command JSON, and the controlled committed local histories complete without invoking their callback. The local-executor control proves the factory's exact selected delay list reaches the existing repeat behavior without treating wall time as evidence. Schedule-to-close remains a separate unchanged command deadline.

I independently reviewed the seven-file delta and ran the two affected test modules: 45 tests pass. Focused Ruff and mypy checks pass. The current exact-head hosted matrix, package, corpus, integration, CodeQL, Sonar and target-branch qualification are all terminal success; the two effectful installed cells remain intentionally skipped in ordinary CI.

This is source/API approval only. Exact candidate/package qualification, protected publication, normal-registry installed evidence and stable/root documentation remain separate delivery gates. It does not authorize a timer-redrive dispatch or satisfy the unrelated physical timer-row criterion.

@rmcdaniel

Copy link
Copy Markdown
Member Author

General accepted-API/source review: PASS for exact 6c94f6a152ec5434c607b427a36b5af855403a70 / tree ae5f66480b2d3c39d424b115cab989c981d1a226.

I read all seven changed files and the unchanged serializer/backoff implementation. The additive keyword-only ActivityRetryPolicy.exponential(...) boundary is consistent with #219: finite60-second default, finite non-negative explicit maximum including zero/fractions, positive integer total attempts including the first, finite non-negative initial interval, coefficient at least one, and explicit refusal of None/nonfinite/unsupported parameters. Error-type inputs are copied. Existing rounding applies the cap before whole-command-second ceiling, as the documentation and fractional controls state.

The constructor defaults and _backoff_seconds/to_dict code remain unchanged. The factory emits the same existing max-attempt/list/error-type wire shape; it does not reinterpret old omitted/None maxima or explicit lists. The recorded2.17.2 command-byte fixtures, replay-without-callback controls and unchanged retained history cover that compatibility boundary. Source docs/examples select the new factory explicitly; default9-attempt generation is [1,2,4,8,16,32,60,60]. The local executor control uses virtual sleeps and is correctly described at that scope.

This clears the requested source/API choice. It does not supply registry-installed timing or publication authority. Exact current CI, planned2.18.0 package/installed acceptance and stable/API/root-guide delivery remain the owner's gates before the corresponding #219 criterion closes. I also checked the unchanged portal workflow: ordinary main builds have stable=false; protected stable deployment requires an explicit published stable tag, preserving the released2.17.2 guide until that separate handoff. No additional release of the unchanged legacy API is required.

@rmcdaniel
rmcdaniel marked this pull request as ready for review November 14, 2026 04:27
@rmcdaniel
rmcdaniel merged commit 5f3ecc9 into main Nov 14, 2026
23 checks passed
@rmcdaniel
rmcdaniel deleted the sdk-python/219-generated-backoff-cap branch November 14, 2026 04:28
@rmcdaniel

Copy link
Copy Markdown
Member Author

Normal merge 5f3ecc91509b005d9ee34c890c8ca670cce529d2 has tree ae5f66480b2d3c39d424b115cab989c981d1a226, exactly equal to reviewed 6c94f6a152ec5434c607b427a36b5af855403a70; parents are accepted main 717beb7b… and that exact head. All 23 head checks are terminal: 21 SUCCESS and the two intended manual-cell SKIPs. Exact PR Sonar has no OPEN/CONFIRMED issues. Security source/API PASS and General semantics PASS bind this tree. The topic branch is independently absent after expected-head deletion.

Accepted-main checks are running separately. The additive factory is merged source, not a published SDK API yet. The next owned slice prepares 2.18.0 and the bounded candidate/registry retry case through the existing closed installed consumer profile; exact artifact review, installed proof, protected publication and stable/root docs remain required. No timer dispatch or physical-row observation is selected by this work.

@rmcdaniel

Copy link
Copy Markdown
Member Author

Accepted-main readback is complete at 5f3ecc91509b005d9ee34c890c8ca670cce529d2, tree ae5f66480b2d3c39d424b115cab989c981d1a226, exactly equal to both independent source reviews. All 22 actual-main commit contexts are terminal without failure; manual installed cells remain skipped. Main/source API delivery is therefore integrated, while the published SDK is still 2.17.2.

The next owned package/installed slice is draft #329: 2.18.0 metadata, a fixed scalar-local retry case and approved candidate/identical-registry artifact handling through the existing closed internal consumer. Its source review/current CI precede exact build selection. Artifact review, installed candidate proof, protected publication, registry repeat and stable/root docs remain explicit before shared #219 delivery can be claimed. No timer or physical-row scope is expanded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant