Skip to content

[Router] Consolidate duplicate ConnectionMode enums #11901

@YouNeedCryDear

Description

@YouNeedCryDear

Problem Statement

The codebase currently has two separate ConnectionMode enums with the same name but in different modules:

  1. config::types::ConnectionMode (in src/config/types.rs)
  2. core::worker::ConnectionMode (in src/core/worker.rs)

This duplication creates confusion, maintenance burden, and potential for bugs when the wrong type is imported.

Current State

config/types.rs ConnectionMode

#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
#[serde(tag = "type")]
pub enum ConnectionMode {
    #[default]
    #[serde(rename = "http")]
    Http,
    #[serde(rename = "grpc")]
    Grpc,  // ← Simple unit variant
}

core/worker.rs ConnectionMode

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ConnectionMode {
    Http,
    Grpc {
        port: Option<u16>,  // ← Struct variant with port field
    },
}

Key Differences

Aspect config::ConnectionMode core::ConnectionMode
Grpc variant Unit variant (no fields) Struct variant with port: Option<u16>
Derives Serialize, Deserialize, Default Eq, Hash
Purpose User-facing configuration Runtime worker connection
Serde Has JSON parsing annotations No serde support

Problems

  1. Name collision confusion: Same name in same crate causes import ambiguity
  2. No conversion exists: No impl From to convert between the two types
  3. Duplication of concept: Both represent "how to connect to workers"
  4. Maintenance burden: Changes must be kept in sync across two definitions
  5. Easy to import wrong type: Developers may accidentally use the wrong one

Proposed Solution

Consolidate into a single unified ConnectionMode enum that serves both configuration and runtime purposes:

// Location: src/core/worker.rs or src/types.rs
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum ConnectionMode {
    Http,
    Grpc {
        #[serde(skip_serializing_if = "Option::is_none")]
        #[serde(default)]
        port: Option<u16>,
    },
}

How This Works

For Configuration (JSON/YAML):

  • Users can omit port: { "type": "grpc" }Grpc { port: None } (auto-detect)
  • Users can specify port: { "type": "grpc", "port": 50051 }Grpc { port: Some(50051) }
  • The #[serde(skip_serializing_if = "Option::is_none")] keeps serialized output clean

For Runtime:

  • Port information is available when needed
  • Can derive Eq and Hash for use in collections (WorkerRegistry)
  • Maintains all runtime capabilities

Benefits

One source of truth - Single definition eliminates confusion
Config flexibility - Optional port field works for both simple and advanced configs
Runtime capability - Port information available when needed
All traits supported - Can derive Serialize, Deserialize, Eq, Hash simultaneously
Cleaner imports - Only one ConnectionMode to import
Better maintainability - Changes only need to be made in one place

Migration Steps

  1. Add serde derives to core::worker::ConnectionMode:

    #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
    #[serde(tag = "type", rename_all = "lowercase")]
    pub enum ConnectionMode {
        Http,
        Grpc {
            #[serde(skip_serializing_if = "Option::is_none")]
            #[serde(default)]
            port: Option<u16>,
        },
    }
  2. Remove config::ConnectionMode from src/config/types.rs

  3. Update all imports throughout the codebase:

    • Find: use crate::config::ConnectionMode or use crate::config::types::ConnectionMode
    • Replace with: use crate::core::ConnectionMode
  4. Test configuration parsing to ensure JSON/YAML deserialization works correctly

  5. Update tests if any specifically test config parsing

Impact

  • Breaking change: No, the unified type is backward compatible for configs
  • Migration effort: Low - mostly import statement updates
  • Risk: Low - types are structurally compatible
  • Files affected: Approximately 5-10 files with import changes

Additional Context

This issue was discovered while implementing IGW mode multi-router support, where the distinction between the two types caused confusion and led to type mismatch errors. Having a single well-designed type will prevent similar issues in the future.


Related: This consolidation should be done before or in conjunction with the router selection fixes for proper gRPC worker support in IGW mode.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions