Skip to content

Add transport injection, error policies, and session renewal to clients #329

Description

@shinybrar

Problem Statement

Users and automated systems operating the CANFAR Science Platform encounter three key limitations in the existing client and CLI:

  1. Connection Pool Sharing & Multi-User Service Inefficiency: Services running on behalf of multiple users (e.g. Science Portal, workflow orchestrators) cannot share a connection pool across users. Injected transports were previously handled via private overrides that were removed, and client shutdown previously closed caller-owned transports. Furthermore, using transports with per-user X.509 client certificates leads to silent credential dropping because underlying HTTP libraries bypass client certificates when custom transports are set.
  2. Error Ambiguity in Session Lifecycle Methods: Session operations (create, info, logs, events, destroy) fail silently to [], None, or False under default behavior. Callers cannot differentiate between transient platform outages (5xx, connection timeouts) and request rejections (4xx, quota limits, authorization failures). When operating on batches of sessions, callers need both the successfully processed session identifiers and the specific errors for failed ones.
  3. Inability to Renew Interactive Sessions Programmatically or via CLI: Interactive Sessions on a Science Platform Server expire after their configured lifetime (typically 4 days). While the Science Platform backend and Science Portal support session renewal via POST session/{id}?action=renew, the CANFAR Python client and CLI have no renewal mechanism, forcing users to manually interact with the web interface to prevent session expiration.
  4. Code Maintainability: The core Session management client module has grown excessively large, mixing top-level client facades, batch task dispatching, regex matching, URL formatting, and error-handling utilities.

Solution

Deliver a unified enhancement covering:

  1. Public Transport Injection on HTTP Client: Support transport on the HTTP client configuration, enabling shared connection pools for Bearer token requests, preserving caller ownership by preventing client closes from destroying injected pools, and validating against invalid sync/async or X.509 pairings.
  2. Standardized Error Handling Policy (errors="ignore" | "raise"): Introduce a configurable error mode at both the client instance level (defaulting to "ignore" and overridable via environment variable) and per-method keyword overrides, raising a structured exception containing partial results and per-item HTTP errors on failure.
  3. Consolidated Session Helpers: Extract internal session-management utilities, batch executors, URL builders, and failure handlers into a consolidated helper module, keeping the Session client lean and modular.
  4. Interactive Session Renewal API & CLI: Add renew() to both synchronous and asynchronous Session clients returning per-session success booleans, alongside a dedicated canfar renew CLI command that extends session lifetimes immediately with clear human-readable status.

Implementation Decisions

1. Transport Injection on HTTPClient

  • HTTPClient gains an optional transport setting accepting either a synchronous or asynchronous httpx2 transport.
  • The transport field is excluded from serialization and environment variable binding.
  • Client factory logic validates transport compatibility:
    • Synchronous client requires a synchronous BaseTransport.
    • Asynchronous asynclient requires an AsyncBaseTransport.
    • Mismatches raise TypeError.
  • Combining transport with X.509 client credentials (runtime certificate or active X.509 Authentication Record) raises ValueError at construction, because custom transports bypass client SSL verification contexts.
  • Injected transports are wrapped so that client.close() and client.aclose() leave the underlying transport open; caller retains ownership and responsibility for closing the pool.
  • Request timeouts continue to be enforced per request; connection limits are managed directly on the injected transport.

2. Error Mode Policy (errors="ignore" | "raise")

  • Session and AsyncSession support an errors field taking "ignore" or "raise", defaulting to "ignore", configurable via environment variable CANFAR_ERRORS.
  • All session lifecycle methods (create, info, logs, events, destroy, destroy_with, and renew) accept an optional keyword-only errors: Literal["ignore", "raise"] | None = None parameter. When None, the instance-level self.errors applies.
  • Under errors="raise":
    • All requests in a batch run to completion first.
    • If any request encountered an httpx2.HTTPError, a new SessionRequestError exception is raised.
    • Prototype exception contract:
      class SessionRequestError(Exception):
          operation: str
          results: Any
          errors: dict[str | int, HTTPError]
    • The first failure is attached as __cause__.
    • Authentication errors and parameter validation errors continue to raise immediately regardless of error mode.
    • fetch() and stats() retain their existing behavior of raising immediately on HTTP error.

3. Helper Consolidation

  • Extract internal helpers from the session client into a dedicated session helper module under the canfar/helpers/ namespace.
  • Relocated utilities include URL path construction, identifier normalization, task result filtering, regex compilation, connection URL resolution, deletion failure handling, and renewal failure handling.
  • Private failure helper prototype:
    def _renew(session_id: str, exc: BaseException | None = None) -> bool: ...

4. Interactive Session Renewal

  • Add renew(ids, *, errors=None) -> dict[str, bool] to both Session and AsyncSession.
  • HTTP request uses POST session/{session_id} with form parameter action=renew.
  • Returns a mapping of session ID to boolean indicating whether renewal succeeded.
  • Under errors="raise", failures populate results[session_id] = False and record the exception in SessionRequestError.errors.
  • Sync and async method signatures remain strictly parallel and are tracked in the lifecycle signature suite.

5. CLI Command canfar renew

  • Implement canfar.cli.renew:renew_sessions accepting one or more session IDs.
  • Registered lazily in root CLI command dictionary under the "Session Management" panel with no_args_is_help=True.
  • Non-destructive operation: executes immediately without interactive confirmation prompts.
  • Emits active server banner and prints formatted human-readable success and error summaries.

Activity

  1. shinybrar commented on Oct 7, 2026

    @shinybrar
    ContributorAuthor

    Jira: CADC-16204. This issue holds the authoritative spec.

  2. shinybrar commented on Oct 8, 2026

    @shinybrar
    ContributorAuthor

    @sipho-sarao Here is the proposed plan for implementing support for custom transports and a regimen to re-raise errors in the canfar clients. Any feedback from you and your team would be welcomed, especially if this implementation checks all your goals. Let us know

  3. self-assigned this
    on Oct 8, 2026
  4. added theissue type on Oct 8, 2026
  5. changed the title [-]Add public transport and errors options to Session clients[/-] [+]Add transport injection, error policies, and session renewal to Session clients[/+] on Oct 8, 2026
  6. shinybrar commented on Oct 9, 2026

    @shinybrar
    ContributorAuthor

    Implemented in #331.

  7. changed the title [-]Add transport injection, error policies, and session renewal to Session clients[/-] [+]Add transport injection, error policies, and session renewal to clients[/+] on Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestready-for-agentFully specified and ready for an AFK agent

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions