Skip to content

Extend RunConfig with replica and cache-size fields #4203

@yrobla

Description

@yrobla

Description

Add two new fields to RunConfig in pkg/runner/config.go: BackendReplicas *int32 for configuring the desired StatefulSet replica count, and SessionCacheSize int for bounding the local LRU session cache. These fields are the foundation for all horizontal scaling work in the proxyrunner epic — downstream tasks (RC-11, RC-12, RC-13) read these values to control StatefulSet replica management and session cache sizing.

Context

Part of epic stacklok/stacklok-epics#263 — Horizontal Scaling for Proxyrunner (THV-0047). RunConfig is ToolHive's serializable workload configuration and is part of the public API contract. This task extends it with two optional fields that are zero-value-safe: nil BackendReplicas means "don't touch replicas" (preserving HPA/kubectl control), and zero SessionCacheSize will cause consuming code to apply a sensible default of 1000.

Dependencies: None
Blocks: TASK-002 (Configurable StatefulSet replica count), TASK-004 (Implement RoutingStorage)

Acceptance Criteria

  • RunConfig struct in pkg/runner/config.go has a new BackendReplicas *int32 field with JSON tag json:"backend_replicas,omitempty" and YAML tag yaml:"backend_replicas,omitempty"
  • RunConfig struct has a new SessionCacheSize int field with JSON tag json:"session_cache_size,omitempty" and YAML tag yaml:"session_cache_size,omitempty"
  • Both fields are optional and zero-value-safe: existing RunConfig JSON/YAML files that do not include the new fields continue to deserialize without error and without changing existing behavior
  • BackendReplicas is a pointer type (*int32) so that nil can be distinguished from an explicit value of 0
  • Doc comments follow the existing field comment style in RunConfig and explain the nil/zero-value semantics for each field
  • Round-trip serialization test: a RunConfig with both fields set serializes to JSON/YAML and deserializes back with values preserved
  • Round-trip serialization test: a RunConfig without the new fields (omitted) deserializes with BackendReplicas == nil and SessionCacheSize == 0
  • All existing tests pass without modification

Technical Approach

Recommended Implementation

Add the two fields to the RunConfig struct in pkg/runner/config.go, following the existing field ordering and comment conventions. No changes to constructor functions, serialization helpers, or validation logic are needed — the omitempty tags handle backward-compatible serialization, and the zero-value semantics are defined by the consuming code in TASK-002 and TASK-004.

Patterns & Frameworks

  • Follow the existing field style in RunConfig: each field has a Go doc comment, JSON tag, and YAML tag. Fields that are optional use omitempty on both tags.
  • Use *int32 (pointer) for BackendReplicas to allow nil-vs-zero distinction, consistent with how Kubernetes API types represent optional integer fields (e.g., appsv1.StatefulSetSpec.Replicas).
  • Use plain int (not a pointer) for SessionCacheSize since zero is a meaningful sentinel that consuming code maps to a default — consistent with how other integer config fields in the repo are handled.
  • RunConfig is documented as part of ToolHive's API contract (see the struct comment at line 46); do not change the schema version CurrentSchemaVersion in this PR — these additions are backward-compatible and additive.

Code Pointers

  • pkg/runner/config.go — The RunConfig struct starting at line 46; add the new fields here, following the comment and tag style of existing fields (e.g., K8sPodTemplatePatch at line 150 is a good nearby example of a Kubernetes-specific optional field with both JSON and YAML tags)
  • pkg/transport/session/storage.go — The Storage interface; understanding this helps clarify why SessionCacheSize is needed (it bounds the LRU cache used by RoutingStorage in TASK-004)
  • pkg/container/kubernetes/client.go lines 401–404 — The WithReplicas(1) call that TASK-002 will make conditional on BackendReplicas != nil

Component Interfaces

The two new fields to add to RunConfig:

// BackendReplicas is the desired StatefulSet replica count for the MCP backend.
// When nil, WithReplicas is omitted from the StatefulSet apply spec so that
// HPA or kubectl retains control of the replica count.
BackendReplicas *int32 `json:"backend_replicas,omitempty" yaml:"backend_replicas,omitempty"`

// SessionCacheSize is the maximum number of sessions held in the proxyrunner's
// local LRU cache. When 0, a default of 1000 is used by the consuming code.
SessionCacheSize int `json:"session_cache_size,omitempty" yaml:"session_cache_size,omitempty"`

Testing Strategy

Unit Tests

  • Serialize a RunConfig with BackendReplicas set to a non-nil value (e.g., int32(3)) and SessionCacheSize set to 500; unmarshal the JSON output and assert the fields round-trip correctly
  • Serialize a RunConfig that omits both new fields (i.e., zero-valued RunConfig{}); assert the JSON output does not contain backend_replicas or session_cache_size keys (omitempty behavior)
  • Deserialize a JSON payload that does not include backend_replicas or session_cache_size; assert BackendReplicas == nil and SessionCacheSize == 0
  • Deserialize a JSON payload that sets backend_replicas: 2; assert BackendReplicas != nil && *BackendReplicas == 2

Integration Tests

  • No integration tests required for this task — the field additions are structural only and exercised by downstream tasks

Edge Cases

  • backend_replicas: 0 in JSON — assert this deserializes to BackendReplicas pointing to int32(0), not nil (important: 0 is an explicit value distinct from omitted)
  • YAML round-trip with both fields set — assert values are preserved

Out of Scope

  • Validation logic for BackendReplicas or SessionCacheSize (e.g., range checks) — deferred to consuming code in TASK-002 and TASK-004
  • Wiring BackendReplicas into the Kubernetes client (TASK-002)
  • Wiring SessionCacheSize into RoutingStorage construction (TASK-004, TASK-006)
  • Changes to CurrentSchemaVersion — these fields are backward-compatible additions
  • CLI flags or operator CRD changes to expose these fields — operator/CLI concerns outside this task

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestgoPull requests that update go codekubernetesItems related to KubernetesscalabilityItems related to scalability

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions