Skip to content

Document heartbeating a long blocking activity from a helper thread #199

Closed

Description

@rmcdaniel

Problem

Python users with one long blocking call, such as a library call that outlasts the heartbeat timeout, need to heartbeat from a helper thread, and there's no supported way documented. They reach for private APIs or copy contextvars by hand.

  • The Python guide says to call activity.context().heartbeat_sync(details) from a synchronous callback.
  • activity.context() reads a context variable. A thread the activity starts doesn't inherit it, so calling it there raises "activity.context() called outside of an activity execution".
  • heartbeat_sync itself works from any thread other than the worker's event loop, because it runs the request on that loop with the original attempt. Capturing the context object inside the activity is enough, but nothing says so.
  • The heartbeat guide covers heartbeating at work-loop boundaries, but not a single call that blocks longer than the heartbeat window.

Source-verified, not reproduced.

Acceptance criteria

  • The Python guide shows heartbeating during one long blocking call from a helper thread, using the context captured inside the activity, and stopping the helper when the call returns or raises.
  • It states that heartbeat_sync is safe from any thread except the worker event loop, and that activity.context() works only in the activity's own thread.
  • It explains the trade-off: a helper keeps reporting liveness even if the main call hangs, so bound it with a deadline. It also says how the activity should stop when heartbeat_sync raises ActivityCancelled or ActivityLeaseAuthorityLost in the helper.

Activity

  1. rmcdaniel commented on Oct 22, 2026

    @rmcdaniel
    MemberAuthor

    Accepted as P3 documentation work, owned by General. The existing captured ActivityContext.heartbeat_sync API supplies the needed thread-safe heartbeat operation; this does not currently require a new public API.

    The guide must demonstrate capturing the context before starting the helper, bounded helper lifetime and shutdown on both return and exception, and propagation of cancellation or lease-authority loss back to work that supports cooperative interruption. It must not imply that an exception in a helper can forcibly interrupt an arbitrary blocking library call. Give that call its own timeout or cancellation mechanism so the helper cannot keep a hung attempt alive indefinitely.

    Next: exercise the complete recipe against the current published SDK, including cancellation, authority loss and helper teardown, then update the Python and heartbeat guides and all seven translated copies together. The urgent CI trust remediation and protected releases already in progress retain priority.

  2. rmcdaniel commented on Oct 22, 2026

    @rmcdaniel
    MemberAuthor

    The documentation fix is prepared in SDK #200
    at 52cd64a5 and Website #360
    at 4f6db301. The complete copyable recipe lives in the SDK reference; the
    Python and heartbeat guides explain the boundary in all eight offered
    languages and link to it. No SDK runtime or public API change is needed.

    Seven focused checks pass with the normally installed published 2.9.0 wheel,
    including original task/attempt/worker identity, helper context capture,
    typed cancellation and authority loss, transport failure, normal/error join
    and event-loop refusal. The client responses are constructed fixtures, not
    live Server acceptance. Ruff and all 105 guides' existing translation/source
    and code-parity checks pass.

    Normal CI and both documentation deployments are still pending. The website
    will follow the SDK portal deployment to avoid publishing a broken recipe
    anchor. The issue stays open until the live pages are checked. The recipe
    requires bounded work and transport retries and cooperative cancellation; it
    does not claim an auxiliary thread can forcibly interrupt a blocking library.

  3. rmcdaniel commented on Oct 23, 2026

    @rmcdaniel
    MemberAuthor

    Delivered through SDK #200
    and Website #360.

    • SDK source is merged at 6bf63a1226fb1607b09ecced2ecce9b5c6afe0a6, exact
      qualified tree 6b193f0247de26cf75243e9f9326884434ebdb74. All 18 final
      checks pass, including integration and target-branch qualification. Sonar's
      valid composite-assertion finding is corrected; zero OPEN/CONFIRMED remains.
    • Portal deployment 39878700601
      passes, and the live deployment-audit JSON matches that merge. The
      complete helper-thread recipe
      is served at its actual public anchor.
    • Website source is merged at 526fd0e98364cf94d805964b7d0ee02eef6a728d,
      exact qualified tree 75468eb771b014db34a52a521ff5be7bf655c119, after all
      nine checks and all 105 guides' translation/hash/code-parity controls pass.
      Deployment 39880730912
      passes. Sixteen actual public HTTP checks verify both guides in English,
      German, Spanish, French, Brazilian Portuguese, Ukrainian, Japanese and
      Simplified Chinese: localized helper headings, stable section anchors,
      working SDK-reference links and the heartbeat-guide cross-links are present.

    The copyable helper captures the original context, uses the original worker
    loop/task/attempt, and stops/joins on return or error. It propagates typed
    cancellation, authority loss and transport failures. The guidance requires a
    finite operation deadline and cooperative cancellation; it distinguishes
    liveness from progress. Seven focused controls pass against a normal installed
    PyPI 2.9.0 wheel with constructed client responses, not a new live Server cohort.
    This is documentation delivery and does not publish PyPI 2.9.1.

  4. added
    status:doneDerived from the authoritative closed issue state
    completion:evidence-verifiedAcceptance, fixed version, and required operational evidence are publicly verified
    on Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    completion:evidence-verifiedAcceptance, fixed version, and required operational evidence are publicly verifiedpriority:P3Lower-priority product improvementstatus:doneDerived from the authoritative closed issue state

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions