Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Fix early-release regression: avoid double-logout on same TM1 session#149

Merged
nicolasbisurgi merged 1 commit into
mastercubewise-code/rushti:masterfrom
fix/early-release-double-logoutcubewise-code/rushti:fix/early-release-double-logoutCopy head branch name to clipboard
May 1, 2026
Merged

Fix early-release regression: avoid double-logout on same TM1 session#149
nicolasbisurgi merged 1 commit into
mastercubewise-code/rushti:masterfrom
fix/early-release-double-logoutcubewise-code/rushti:fix/early-release-double-logoutCopy head branch name to clipboard

Conversation

@nicolasbisurgi

@nicolasbisurgi nicolasbisurgi commented May 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes a regression introduced in v2.1.0 by the early-session-release feature (#135 / #136).

Every rushti run against a single-instance workflow has been emitting this warning at the end of the run since v2.1.0:

WARNING - Failed to logout from tm1srv01: There are multiple cookies with name, 'TM1SessionId'

The workflow itself succeeds; the warning is end-of-run logout cleanup noise — but it's persistent and confusing. Multi-instance workflows hit it too whenever an instance finishes its tasks before the workflow as a whole.

Root cause

_logout_instance (added in v2.1.0) calls tm1_services[name].logout() for early release but does not remove the entry from tm1_services afterward. The end-of-run logout() call in cli.py's finally block then iterates the same dict and calls .logout() again on the same TM1Service instance.

Two logouts on the same requests.Session:

LOGOUT #1 (early release)        LOGOUT #2 (end-of-run cleanup)
        |                                 |
        v                                 v
DELETE /api/v1/ActiveSession      DELETE /api/v1/ActiveSession
        |                                 |
   server replies                    server replies, the response now
   normally                          appends a TM1SessionId cookie
   single cookie in jar              with different (Path, Domain,
                                     Secure) attributes — RFC 6265
                                     stores it as a distinct cookie
                                     |
                                     v
                              TM1py's name-only lookup
                              `cookies.get("TM1SessionId")`
                              raises CookieConflictError
                                     |
                                     v
                              caught at execution.py:772
                              → WARNING emitted

This was confirmed locally by reproducing the duplicate cookie state with a minimal diagnostic — single cookie before logout, two cookies after a second logout call on the same session. Single-logout flows (e.g. read_taskfile_from_tm1) work cleanly; only the early-release path triggers the double-logout pattern.

The fix (Option A)

On a successful logout — both in _logout_instance and in the end-of-run logout() — remove the entry from tm1_services. The dict now consistently represents live connections, and the end-of-run pass naturally skips anything already released. Failed logouts still leave the entry in place so the end-of-run cleanup retries them (existing safety net preserved).

The redundant released_instances tracking set in work_through_tasks_dag is removed — the dict mutation IS the tracking mechanism now.

Diff shape

  • src/rushti/execution.py

    • _logout_instance now del tm1_services[instance_name] on success; docstring updated.
    • logout (end-of-run) does the same; iterates list(tm1_services.keys()) for safety.
    • work_through_tasks_dag drops the released_instances set and the redundant membership guard.
  • tests/unit/test_early_session_release.py

    • Existing tests that asserted the old "entry stays" behavior updated to assert "entry removed".
    • New TestNoDoubleLogoutAfterEarlyRelease class with 4 regression tests that mirror the actual cli.py lifecycle (work_through_tasks_daglogout) and pin:
      • single-instance: mock_tm1.logout.call_count == 1 (was 2 pre-fix)
      • multi-instance: each instance logs out exactly once
      • failed early release falls back to final logout (retry behavior preserved)
      • preserved + no-force is skipped by both passes

Test plan

  • 23 tests in test_early_session_release.py pass (4 new, 19 existing/updated)
  • Full unit suite: 612 passed, 5 skipped
  • ruff check clean
  • black --check clean
  • CI Unit Tests pass (Python 3.9, 3.13)
  • CI Integration Tests pass (TM1-required, ~7 min)
  • Manual: rushti run against a single-instance workflow no longer prints the cookie warning

Compatibility

  • No CLI surface change.
  • No public-API change. _logout_instance is module-private (leading underscore); the public logout function keeps the same signature, only adds del on success — callers that handed in tm1_services and didn't reuse it after logout returns are unaffected.
  • Behavior change is exactly what the original v2.1.0 PR intended: each session is logged out once, no orphan double-logouts.

Suggested release: 2.1.1 (patch).

🤖 Generated with Claude Code

Since v2.1.0 (#136, early session release) RushTI has been calling
``logout()`` twice on the same TM1Service for any single-instance
workflow, and for multi-instance workflows whenever an instance has
its tasks finish before the workflow as a whole.

The first logout (from ``_logout_instance`` in the DAG loop)
succeeded server-side, but the response added a second
``Set-Cookie: TM1SessionId=...`` to the requests Session's cookie
jar — with different attributes (Path, Domain, Secure) than the
original. RFC 6265 treats those as distinct cookies, so the jar
ended up with two ``TM1SessionId`` entries.

The second logout (from the end-of-run ``logout()`` in cli.py's
finally block) iterated the same dict, called ``.logout()`` on the
already-released TM1Service, and TM1py's name-only cookie lookup
tripped on the duplicate. Net result was the noisy warning:

  WARNING - Failed to logout from tm1srv01:
            There are multiple cookies with name, 'TM1SessionId'

Fix (Option A from the analysis): on a successful logout — both in
``_logout_instance`` and in the end-of-run ``logout()`` — remove the
entry from ``tm1_services``. The dict now consistently represents
*live* connections, and the end-of-run pass naturally skips anything
already released. The redundant ``released_instances`` tracking set
is removed.

A failed logout still leaves the entry in place so the end-of-run
cleanup can retry it (existing safety net preserved).

Tests:
- Existing tests that asserted the old "entry stays" behavior updated
  to reflect the new "entry removed" invariant.
- New ``TestNoDoubleLogoutAfterEarlyRelease`` regression tests pin
  the bug end-to-end (work_through_tasks_dag → logout) for single
  and multi-instance, plus the failure-path retry behavior and the
  preserved-without-force skip.

23 tests in test_early_session_release.py pass (+4 new). Full unit
suite: 612 passed, 5 skipped.

Closes the cookie-conflict warning seen on every ``rushti run`` for
single-instance workflows since v2.1.0.
@nicolasbisurgi nicolasbisurgi added the release:patch Triggers patch version bump (e.g.: 1.4.9 → 1.4.10) label May 1, 2026
@nicolasbisurgi
nicolasbisurgi merged commit c903ad5 into master May 1, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release:patch Triggers patch version bump (e.g.: 1.4.9 → 1.4.10)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Morty Proxy This is a proxified and sanitized view of the page, visit original site.