Skip to content

feat(session): add NewManagerWithRedis constructor (RC-7)#4236

Open
yrobla wants to merge 2 commits intomainfrom
issue-4208
Open

feat(session): add NewManagerWithRedis constructor (RC-7)#4236
yrobla wants to merge 2 commits intomainfrom
issue-4208

Conversation

@yrobla
Copy link
Contributor

@yrobla yrobla commented Mar 19, 2026

Summary

Wires the Redis storage backend into the session manager lifecycle (RC-7), and establishes UUID as the canonical session ID format across all storage backends and proxy transports.

NewManagerWithRedis constructor (RC-7)

  • NewManagerWithRedis(ctx, ttl, factory, cfg) accepts a RedisConfig and constructs a Redis-backed *Manager via NewRedisStorage + NewManagerWithStorage
  • ctx is used for the initial Ping during construction (improvement over the original issue spec, which did not thread context through)
  • Existing NewManager, NewTypedManager, and NewManagerWithStorage signatures are unchanged

UUID enforcement (breaking API change — see compatibility notes below)

  • Manager now validates that all session IDs are UUID-format on AddWithID, AddSession, UpsertSession, and Delete
  • validateSessionID is an unexported helper that enforces this consistently across all storage backends (previously RedisStorage alone had per-operation UUID checks, creating a store-then-can't-load inconsistency)
  • RedisStorage no longer does its own UUID checks; validation lives exclusively in Manager

Non-UUID Mcp-Session-Id normalization in transparent proxy

  • The MCP spec does not mandate UUID format for Mcp-Session-Id; upstream servers may issue arbitrary strings
  • normalizeSessionID (new, in pkg/transport/proxy/transparent) maps any non-UUID external session ID to a deterministic UUID v5 (RFC 4122 URL namespace), so the transparent proxy can store upstream-issued IDs in the UUID-only session manager without a reverse-mapping table
  • Applied at all three callsites where the transparent proxy reads Mcp-Session-Id from upstream responses or SSE stream data

Fixes #4208

Type of change

  • Bug fix
  • New feature
  • Refactoring (no behavior change)
  • Dependency update
  • Documentation
  • Other (describe):

Test plan

  • Unit tests (task test)
  • E2E tests (task test-e2e)
  • Linting (task lint-fix)
  • Manual testing (describe below)

Changes

File Change
pkg/transport/session/manager.go Add NewManagerWithRedis, validateSessionID; wire UUID validation into all manager methods
pkg/transport/session/storage_redis.go Remove per-operation UUID checks (moved to Manager); add Username ACL field wiring; add KeyPrefix trailing-colon validation; sliding-window TTL godoc
pkg/transport/session/redis_config.go Add Username field for Redis 6+ ACL auth
pkg/transport/proxy/transparent/session_id.go New: normalizeSessionID — UUID pass-through or deterministic UUID v5 derivation
pkg/transport/proxy/transparent/transparent_proxy.go Apply normalizeSessionID at all Mcp-Session-Id callsites
pkg/transport/proxy/transparent/sse_response_processor.go Apply normalizeSessionID before AddWithID
Tests Updated throughout to use UUID-format session IDs; new tests for Redis round-trips, ACL auth, UUID validation, and normalizeSessionID

Does this introduce a user-facing change?

No direct user-facing change. Internal plumbing for Redis-backed horizontal scaling (THV-0047). The Redis constructor is not yet wired into the vMCP server (deferred to RC-8).

Special notes for reviewers

Compatibility: Manager.AddWithID, AddSession, UpsertSession, and Delete now reject non-UUID IDs with "invalid session ID format". All existing toolhive call sites generate UUIDs internally, so there is no runtime regression. The transparent proxy is the only place that ingests externally-sourced session IDs; normalizeSessionID handles that path.

Sliding-window TTL: RedisStorage uses GETEX on every Load to refresh the TTL, meaning sessions remain alive indefinitely while actively used. Revocation requires an explicit Delete. No absolute max lifetime is enforced; a MaxLifetime/CreatedAt check is the noted path forward if a hard cap is needed.

@yrobla yrobla requested a review from Copilot March 19, 2026 14:29
@github-actions github-actions bot added the size/S Small PR: 100-299 lines changed label Mar 19, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a Redis-backed session manager constructor to wire the Redis storage backend into the session.Manager lifecycle, without changing existing NewManager / NewTypedManager signatures.

Changes:

  • Add NewManagerWithRedis(ttl, factory, cfg) constructor that builds RedisStorage and delegates to NewManagerWithStorage
  • Add unit tests covering NewManagerWithRedis success/error paths and asserting existing constructors still use LocalStorage

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
pkg/transport/session/manager.go Adds NewManagerWithRedis constructor that creates RedisStorage and returns a Manager via NewManagerWithStorage.
pkg/transport/session/manager_redis_test.go Adds tests for Redis-backed manager construction, basic round-trip behavior, Stop behavior, and LocalStorage defaults for existing constructors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov
Copy link

codecov bot commented Mar 19, 2026

Codecov Report

❌ Patch coverage is 87.09677% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.20%. Comparing base (949ae42) to head (4a6ffaa).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...g/transport/proxy/transparent/transparent_proxy.go 50.00% 0 Missing and 2 partials ⚠️
...nsport/proxy/transparent/sse_response_processor.go 0.00% 0 Missing and 1 partial ⚠️
pkg/transport/session/storage_redis.go 75.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4236      +/-   ##
==========================================
+ Coverage   69.07%   69.20%   +0.12%     
==========================================
  Files         477      478       +1     
  Lines       48074    48096      +22     
==========================================
+ Hits        33207    33283      +76     
+ Misses      12284    12230      -54     
  Partials     2583     2583              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Mar 19, 2026
Base automatically changed from issue-4205 to main March 20, 2026 08:48
Copy link
Contributor

@jhrozek jhrozek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review of the Redis session storage backend. Overall the implementation is well-structured — clean Storage interface compliance, good use of GETEX for TTL refresh, comprehensive tests with miniredis. A few items to consider, mostly around input validation and API completeness.

Generated with Claude Code

@yrobla yrobla requested review from Copilot and jhrozek March 23, 2026 09:15
Wires the Redis storage backend into the session manager lifecycle.
NewManagerWithRedis accepts a RedisConfig and TTL, constructs a
RedisStorage via NewRedisStorage, and delegates to NewManagerWithStorage.
Existing NewManager and NewTypedManager signatures are unchanged.

Closes #4208
@github-actions github-actions bot added size/M Medium PR: 300-599 lines changed and removed size/S Small PR: 100-299 lines changed labels Mar 23, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Redis-backed session storage and a NewManagerWithRedis constructor so the session manager can be instantiated with a Redis backend (supporting horizontal scaling) while keeping existing NewManager / NewTypedManager callers unchanged.

Changes:

  • Introduces RedisStorage + RedisConfig (standalone & sentinel) and TLS support, with TTL-based (sliding window) key expiry behavior.
  • Adds NewManagerWithRedis(ctx, ttl, factory, cfg) which constructs Redis storage and delegates to NewManagerWithStorage.
  • Expands/updates unit tests for Redis storage and manager behavior; updates storage interface docs to clarify TTL refresh semantics on Load.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pkg/transport/session/manager.go Adds NewManagerWithRedis constructor delegating to NewManagerWithStorage.
pkg/transport/session/manager_redis_test.go Adds unit tests covering Redis-backed manager construction and basic behavior.
pkg/transport/session/manager_test.go Updates test IDs to UUID-looking constants (no functional change).
pkg/transport/session/redis_config.go Adds Redis configuration types + default timeout constants.
pkg/transport/session/storage.go Updates Storage.Load doc to allow backend TTL refresh behavior.
pkg/transport/session/storage_redis.go Implements Redis-backed Storage with TLS config + TTL refresh on reads.
pkg/transport/session/storage_redis_test.go Adds comprehensive Redis storage unit tests using miniredis.
pkg/transport/session/serialization.go Removes “unused” comments now that serialization is used by Redis storage.
Comments suppressed due to low confidence (1)

pkg/transport/session/storage_redis.go:108

  • NewRedisStorage performs an eager Ping and fails construction if Redis is unreachable. The linked issue/testing strategy calls out that unreachable addresses should still allow construction (go-redis is typically lazily connected), with errors surfacing on first operation. If startup should not be coupled to Redis availability, consider making Ping optional (or removing it) and relying on operation-time errors; alternatively, update the issue/PR expectations and add tests for the intended fail-fast behavior.
	if err := client.Ping(ctx).Err(); err != nil {
		_ = client.Close()
		return nil, fmt.Errorf("failed to connect to redis: %w", err)
	}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@yrobla yrobla requested a review from Copilot March 23, 2026 09:32
@github-actions github-actions bot added size/M Medium PR: 300-599 lines changed and removed size/M Medium PR: 300-599 lines changed labels Mar 23, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions github-actions bot removed the size/M Medium PR: 300-599 lines changed label Mar 23, 2026
@github-actions github-actions bot added the size/M Medium PR: 300-599 lines changed label Mar 23, 2026
@yrobla yrobla requested a review from Copilot March 23, 2026 09:48
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@yrobla yrobla requested a review from jerm-dro as a code owner March 23, 2026 10:06
@github-actions github-actions bot added size/M Medium PR: 300-599 lines changed and removed size/M Medium PR: 300-599 lines changed labels Mar 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Medium PR: 300-599 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Wire Redis Backend Selection into session.Manager (RC-7)

4 participants