Skip to main content

Route Collision Guard

Prevents route conflicts when publishing APIs by checking if a route is already in use by another service, ensuring routing stability across the platform.

Overview

The Route Collision Guard is an internal, fail-safe mechanism that prevents different services from unintentionally claiming the same API route. It solves the problem of "route stealing," where publishing or activating one service could silently reassign a live API route from another service, leading to unpredictable request routing and service outages.

This guard runs as a prerequisite check within the transaction that publishes or updates a service's routes. It examines the set of routes a service is about to publish and verifies that none of them are already active and owned by a different service within the same tenant.

If a conflict is detected, the guard throws an exception that aborts the entire publication process. This ensures that the existing, live route remains pointed to its original owner, and the new service is not activated. If no conflicts are found, the publication proceeds.

How it Works

The route collision check is triggered whenever a service's routes are published, which can occur during service version activation or a manual synchronization operation. The process is designed to be atomic and fail-closed, preserving the integrity of the existing routing table.

sequenceDiagram
    participant P as API Publisher
    participant A as Admin Platform
    participant G as Route Collision Guard
    participant D as Database

    P->>A: Activate Service Version
    A->>G: assertNoCrossServiceCollision(serviceId, candidates)
    loop For each candidate route
        G->>D: Query for conflicting route
        alt Conflict exists
            D-->>G: Return existing owner's service ID
            G-->>A: throw RouteCollisionException
            A-->>P: Error: Route conflict detected
        else No conflict
            D-->>G: Return empty result
        end
    end
    G-->>A: Return (no exception)
    A->>D: Write new routes to s2r_runtime_route table
    D-->>A: Commit transaction
    A-->>P: Success: Service activated

The mechanism follows these steps:

  1. An API publisher initiates an action that publishes a service's routes (e.g., activating a new version).

  2. Before writing to the s2r_runtime_route table, the platform calls the RouteCollisionGuard.assertNoCrossServiceCollision method. This method receives the ID of the service being published and a list of its candidate routes.

  3. The guard iterates through each candidate route key. A route key is defined by its direction, environment, restMethod, and restPath.

  4. For each key, the guard executes a SQL query against the s2r_runtime_route table to find any active routes that match the key but are owned by a different service.

    select rr.service_id as existing_service_id, s.service_key as existing_service_key
    from s2r_runtime_route rr
    join s2r_service s on s.id = rr.service_id
    where rr.direction = ?
      and rr.environment = ?
      and rr.rest_method = ?
      and rr.rest_path = ?
      and rr.enabled = true
      and rr.service_id <> ?
      and rr.tenant_id = ? -- Simplified representation of the tenant scope filter
    limit 1
    
  5. Conflict Path: If the query returns a result, it means a conflicting route exists. The guard immediately throws a RouteCollisionException, which includes details about the conflicting route and the service that currently owns it. This exception causes the parent database transaction to roll back, preventing any changes to the routing table.

  6. Success Path: If the query finds no conflicting routes for any of the candidates, the assertNoCrossServiceCollision method completes without an exception. The publication process then proceeds to write the new route configurations to the database.

Collision Check Scope

The guard's logic is narrowly scoped to prevent accidental cross-service conflicts while permitting legitimate operations. The following conditions apply:

  • Self-Updates: A service can always republish its own routes. The check explicitly ignores routes owned by the same service that is being published. This allows for service version updates and rollbacks.
  • Tenant Isolation: Route uniqueness is enforced on a per-tenant basis. Two different tenants can own a route with the same path and method without causing a collision. The check is always filtered to the tenant context of the service being published.
  • Directionality: A PUBLISH route and a CONSUME route with the same path do not collide. The direction is part of the unique key for a route.
  • Disabled Routes: The guard only checks against active routes (enabled = true). If a service's routes are disabled, another service can claim those paths without conflict.

API Reference

The RouteCollisionGuard exposes a single method and uses a data record to define candidate routes.

Method: assertNoCrossServiceCollision

Checks a list of candidate routes for conflicts with existing, active routes owned by other services. If a conflict is found, it throws an exception to halt the publication process.

Parameters

NameTypeRequiredDescription
owningServiceIdUUIDYesThe unique identifier of the service being published.
candidatesList<RouteKey>YesA list of route keys the service intends to publish.

Throws

  • RouteCollisionException: Thrown on the first colliding key found. The publication transaction is rolled back.

Data Structure: RouteKey

A record that represents the unique key of a candidate runtime route.

FieldTypeRequiredDescription
directionStringYesThe direction of the route (e.g., PUBLISH, CONSUME).
environmentStringYesThe environment where the route will be active (e.g., production).
restMethodStringYesThe HTTP method of the route (e.g., GET, POST).
restPathStringYesThe URL path of the route (e.g., /v1/widgets).

Troubleshooting

RouteCollisionException

This exception is the primary failure mode for the route collision guard.

  • Condition: An API publisher attempts to activate or publish a service, but one or more of its defined routes are already in use by another active service within the same tenant.
  • Cause: The combination of direction, environment, restMethod, and restPath for a candidate route matches an enabled route in the s2r_runtime_route table that is associated with a different service_id.
  • Resolution: The API publisher must resolve the conflict. The exception details identify the conflicting route and the service_key of the service that currently owns it. To proceed, the publisher must either:
    1. Modify the service definition to change the conflicting route's path, method, or direction.
    2. Decommission or disable the other service that currently owns the route, thereby freeing it for use.

All SOAP-to-REST docs