Skip to content

feat: pluggable session supervisor and :via tuple session naming - #133

Merged
zoedsoupe merged 2 commits into
mainfrom
claude/modest-rhodes-c058ed
Apr 24, 2026
Merged

zoedsoupe merged 2 commits into
mainfrom
claude/modest-rhodes-c058ed

Conversation

@zoedsoupe

Copy link
Copy Markdown
Owner

Problem

Anubis.Server.Supervisor hardcoded DynamicSupervisor in three places, making it impossible to swap in Horde.DynamicSupervisor for distributed deployments. Additionally, Registry.session_name/2 returned plain atoms, preventing Horde.Registry from auto-registering sessions via :via tuples — creating a race condition window between start_child and explicit register_session calls.

Fixes #113.

Solution

Option A — Pluggable session supervisor

Added a :supervisor option to Anubis.Server.Supervisor.start_link/2, mirroring the existing :registry option:

{MyMCPServer,
  transport: {:streamable_http, start: true},
  registry: {Horde.Registry, [name: MyRegistry, keys: :unique, members: :auto]},
  supervisor: {Horde.DynamicSupervisor, [name: MySupervisor, strategy: :one_for_one, members: :auto]}}

The resolved module is stored in persistent_term and used in start_session/2 and stop_session/3. Defaults to {DynamicSupervisor, []} — fully backward compatible.

Option B1 — session_name/2 callback on the Registry behaviour

Added an optional session_name/2 callback to Anubis.Server.Registry:

@callback session_name(registry_name :: term(), session_id()) :: GenServer.name()

Both Registry.Local and Registry.None implement it returning atoms (same behaviour as before). A Horde adapter can return {:via, Horde.Registry, {name, session_id}}, which causes auto-registration on GenServer.start_link — making register_session/3 a no-op and eliminating the race condition entirely.

Registry.resolve_session_name/3 is the new call site in both the StreamableHTTP plug and the SSE transport, falling back to atom naming when the adapter doesn't implement the callback.

Rationale

Followed the existing :registry pluggability pattern for :supervisor — minimal surface, same mental model. The session_name/2 callback keeps naming strategy co-located with the registry adapter that owns it, rather than spreading the logic across transports. Making it @optional_callbacks preserves backward compatibility for existing custom adapters.

@coderabbitai

coderabbitai Bot commented Apr 22, 2026 •

Copy link
Copy Markdown

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Problem

Anubis hardcodes DynamicSupervisor and uses plain atom session names, preventing integration with distributed supervisor/registry solutions like Horde that require pluggable modules and :via tuple naming.

Solution

  • Pluggable Supervisor: Adds :supervisor option to Anubis.Server.Supervisor.start_link/2 (mirroring the existing :registry pattern). The configured supervisor module is stored in persistent_term and used by start_session/2 and stop_session/3.
  • Pluggable Session Naming: Introduces optional session_name/2 callback to the Anubis.Server.Registry behaviour. Adapters can now return :via tuples (e.g., {:via, Horde.Registry, {name, session_id}}) for auto-registration. New resolve_session_name/3 helper falls back to atom naming when the callback is absent.
  • Updated transports: StreamableHTTP and SSE transports now call Registry.resolve_session_name/3 instead of deriving names directly.

Rationale

Maintains backward compatibility while enabling distributed deployments. Follows the existing registry pluggability model and co-locates naming strategy with the registry adapter, eliminating the race condition between start_child and register_session.

Walkthrough

This change introduces configurable session naming and session supervisor selection in the Anubis server. The registry behavior now defines an optional session_name/2 callback allowing adapter-specific session naming (supporting distributed registry patterns like :via tuples), with a deterministic atom-based fallback. Concurrently, the HTTP supervisor now accepts a configurable :supervisor start option to use custom supervisor modules instead of always defaulting to DynamicSupervisor. Session creation paths in SSE and HTTP transports have been updated to resolve session names through the registry's new helper function rather than deriving them from server configuration.

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the main objectives: adding pluggable session supervisor (Option A) and :via tuple session naming support (Option B1).
Description check ✅ Passed The description covers all required template sections (Problem, Solution, Rationale) with clear explanations of the hardcoded DynamicSupervisor issue, race condition, and implementation details.
Linked Issues check ✅ Passed The PR fully addresses both #113 objectives: pluggable supervisor module via :supervisor option, session_name/2 callback enabling :via tuple naming, and backward compatibility. #39 (cowboy bump) is unrelated to code changes.
Out of Scope Changes check ✅ Passed All changes directly address #113 requirements (pluggable supervisor, :via tuple session naming, persistent_term caching, registry adapter callback). The modifications stay focused on the registry and supervisor subsystems.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/modest-rhodes-c058ed

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@zoedsoupe
zoedsoupe merged commit 0a1aadc into main Apr 24, 2026
9 checks passed
@zoedsoupe
zoedsoupe deleted the claude/modest-rhodes-c058ed branch April 24, 2026 12:58
@zoedsoupe zoedsoupe mentioned this pull request Apr 24, 2026
This was referenced Jul 16, 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.

Support pluggable DynamicSupervisor and :via tuple session naming for distributed deployments (Horde, etc.)

1 participant