Skip to content

Add activity sessions sample (affinity comparison and single-session lifecycle) - #399

Draft
THardy98 wants to merge 4 commits into
mainfrom
demo/activity-session-cache
Draft

THardy98 wants to merge 4 commits into
mainfrom
demo/activity-session-cache

Conversation

@THardy98

@THardy98 THardy98 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Add an experimental sample showing how activity sessions keep a workflow's activities on one worker, so they can reuse worker-local conversation history, and how single-session workers bind workflows to stable identities.

  • Each workflow is a conversation of sequential conversation_step activities. Turn n needs every earlier turn. Each worker caches the turns it holds and fetches only the turns it is missing, with simulated latency per turn (--fetch-seconds). The workflow, activity, worker, and fleet code is shared by two entrypoints.
  • activity_sessions.affinity runs a batch of workflows per mode on a fresh worker fleet and compares turns fetched, time spent fetching, and the most workflows any one worker served:
    • none: ordinary task-queue routing; workers keep fetching turns they missed.
    • affinity: turns run inside workflow.activity_session(ActivitySessionOptions(placement=UseWorkflowSession())) on shared session workers (WorkerSessionConfig()); nothing is fetched.
    • single-session: the same on one single-session worker per workflow (SingleSessionAdmission(stable_identity=...)); nothing is fetched and each worker serves one workflow.
  • activity_sessions.single_session shows both sides of single-session binding across the loss of the whole fleet, in four phases: N workflows and M workers start, each worker binds one workflow and the rest get none; the fleet is killed and every workflow stalls; N - M workers with new stable identities run only the unbound workflows while the bound ones stay stalled; the original M workers restart with their stable identities and resume their own workflows.
  • Each run checks its expectations and exits non-zero on failure. A Rich live view shows a turn grid (who ran each turn and what it fetched), stat tiles for the comparison, and workflow and worker status tables with a phase banner for the lifecycle; --no-live prints only the summary.

Requirements and scope

Requires the experimental SDK from temporalio/sdk-python#1979 and a server built from the shivam/agentcore-single-session branch of https://github.com/temporalio/temporal, with sticky activity execution enabled for the namespace. The README explains running with the feature SDK interpreter.

Restarted single-session workers start with an empty cache and fetch the history once; persisting the cache across restarts is a follow-up.

Validation

  • Both entrypoints run against the custom server: affinity comparison (no session fetched 27 turns vs 0 with affinity and single session; up to 5 workflows per worker vs 2 and 1), and all four single-session lifecycle checks pass.
  • Unit tests and the opt-in integration tests (TEMPORAL_TEST_ACTIVITY_SESSION_SAMPLE=1): 13 passed against the custom server.
  • ruff and mypy pass.

@THardy98
THardy98 force-pushed the demo/activity-session-cache branch 2 times, most recently from 3db15f1 to 903ea36 Compare October 29, 2026 16:22
Conversation workflows run turns that each need every earlier turn, which
workers cache locally and otherwise fetch at a simulated cost. The workflow,
activity, worker, and fleet code is shared by the sample's entrypoints.

`activity_sessions.affinity` runs a batch per mode on a fresh fleet and
compares turns fetched and how many workflows shared a worker:

- none: ordinary task-queue routing
- affinity: turns run inside `workflow.activity_session(...)` on shared
  session workers
- single-session: the same on one single-session worker per workflow
`activity_sessions.single_session` shows both sides of single-session binding
across the loss of the whole fleet: bound workers take no further work, every
workflow stalls when the fleet dies, workers with new stable identities run
only the unbound workflows, and the original workers resume their own
workflows when restarted with the same identities. Each phase advances on an
observed condition and records a check.
Shared Rich building blocks render both entrypoints:

- a turn grid: one row per workflow, one cell per turn, labeled with the
  worker that ran it and the turns it fetched, shaded by turns fetched
- stat tiles for the affinity comparison
- a phase banner and workflow and worker status tables (icon, label, and
  status color) for the single-session lifecycle
- a check list

A shared runner re-renders each entrypoint's layout while it runs;
--no-live prints only the summary. Adds Rich as the sample's dependency group.
Run both entrypoints end to end against a session-capable server: the
affinity comparison in every mode, and the single-session lifecycle. Opt in
with TEMPORAL_TEST_ACTIVITY_SESSION_SAMPLE=1.
@THardy98
THardy98 force-pushed the demo/activity-session-cache branch from 903ea36 to e628529 Compare October 29, 2026 17:38
@THardy98 THardy98 changed the title Add workflow-session activity cache sample Add activity sessions sample (affinity comparison and single-session lifecycle) Oct 29, 2026
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