How Route Tables Are Managed in Fabrica-Kit: Master and Read-Only Configurations Explained

Fabrica-Kit manages distributed route tables through a layered interface hierarchy that separates read-only query capabilities from write-capable master operations, using deterministic key formats and pluggable storage backends to handle service registration and discovery.

The go-pantheon/fabrica-kit repository provides a modular routing layer designed for distributed systems, where service instances must register their network addresses and clients must resolve them reliably. Understanding how route tables are managed in fabrica-kit—including the critical distinction between master and read-only configurations—is essential for implementing robust service discovery and preventing stale routing entries in production environments.

Core Architecture of Fabrica-Kit Route Tables

Interface Hierarchy and Capabilities

The routing system is defined in router/routetable/routetable.go through three progressive interfaces that provide increasing levels of access:

  • ReadOnlyRouteTable: Provides basic read operations including BuildKey, Get, and BatchGet for safe address resolution.
  • ReNewalRouteTable: Extends read-only capabilities with RenewSelf and TTL methods for entry renewal and TTL management.
  • MasterRouteTable: The full write interface embedding ReNewalRouteTable, adding mutable operations like Set, SetNxOrGet, GetSet, and GetEx for service registration.

Deterministic Key Structure

Route entries use a deterministic key format defined in router/routetable/routetable.go (lines 62-64):


r_<name>_{<color>}_{<oid>}

This structure allows any node to compute the exact storage location for a service instance identified by its color (logical group) and object ID (oid) without requiring a central registry.

Master Route Table Configuration

Write Operations and Atomic Updates

The masterRouteTable implementation in router/routetable/master.go provides the write-capable interface used by services that own their registration entries:

  • Set: Stores an address under BuildKey(color, uid) with the configured TTL (master.go L40-L47).
  • GetSet: Atomically retrieves the previous address while overwriting it with a new value (master.go L30-L38).
  • SetNxOrGet: Implements idempotent registration by setting the entry only if absent, returning the existing value otherwise (master.go L49-L57).

TTL Management and Self-Renewal

Master tables embed renewalRouteTable from router/routetable/renewal.go to handle TTL configuration and entry renewal:

// Refresh TTL only if the stored value matches currentAddr
err := rt.RenewSelf(ctx, color, oid, currentAddr)

The RenewSelf method prevents "zombie" routes by verifying the stored address matches the caller's expected value before extending the entry's lifetime (renewal.go L55-L66).

Read-Only Route Table Configuration

Query Operations for Service Discovery

The readOnlyRouteTable in router/routetable/readonly.go provides safe, non-mutable access for clients that need to resolve service addresses:

// Single instance lookup
addr, err := rt.Get(ctx, color, oid)

// Batch resolution for multiple instances
addrs, err := rt.BatchGet(ctx, color, []int64{oid1, oid2, oid3})

The BatchGet method efficiently converts object IDs to deterministic keys and retrieves them in a single storage operation (readonly.go L47-L58).

Pluggable Storage Backends

The route table implementations are storage-agnostic, relying on the Data interface defined in router/routetable/routetable.go:

type Data interface {
    Get(ctx context.Context, key string) (string, error)
    GetEx(ctx context.Context, key string, ttl time.Duration) (string, error)
    BatchGet(ctx context.Context, keys []string) ([]string, error)
    Set(ctx context.Context, key, addr string, ttl time.Duration) error
    SetNxOrGet(ctx context.Context, key, addr string, ttl time.Duration) (bool, string, error)
    GetSet(ctx context.Context, key, addr string, ttl time.Duration) (string, error)
    Expire(ctx context.Context, key string, ttl time.Duration) error
    ExpireIfSame(ctx context.Context, key, value string, ttl time.Duration) error
    Del(ctx context.Context, key string) error
    DelIfSame(ctx context.Context, key, value string) error
}

Concrete implementations such as router/routetable/redis/redis.go provide Redis-backed storage, while the interface allows for PostgreSQL, etcd, or custom backends without modifying the routing logic.

Summary

  • Fabrica-Kit implements a layered interface hierarchy (ReadOnlyRouteTable, ReNewalRouteTable, MasterRouteTable) that separates read capabilities from write operations for secure service discovery.
  • Master route tables in router/routetable/master.go provide atomic write operations (Set, GetSet, SetNxOrGet) and TTL management for service registration.
  • Read-only route tables in router/routetable/readonly.go offer safe lookup methods (Get, BatchGet) for clients that only need to resolve addresses.
  • The deterministic key format (r_<name>_{<color>}_{<oid>}) enables distributed nodes to compute entry locations without central coordination.
  • Pluggable storage backends via the Data interface allow integration with Redis, PostgreSQL, or custom stores while maintaining consistent routing semantics.

Frequently Asked Questions

What is the difference between MasterRouteTable and ReadOnlyRouteTable in fabrica-kit?

MasterRouteTable provides full write capabilities including Set, GetSet, and SetNxOrGet operations, allowing services to register and modify their own route entries. ReadOnlyRouteTable restricts operations to Get and BatchGet, enabling dependent services to resolve addresses without risking accidental modifications to the routing state.

How does the renewal mechanism prevent stale routes in fabrica-kit?

The RenewSelf method in ReNewalRouteTable refreshes a route's TTL only if the stored value matches the caller's expected address. This conditional renewal prevents "zombie" routes where a crashed service's entries persist, since only the current owner with the correct address can extend the entry's lifetime.

What storage backends are supported for route tables in fabrica-kit?

Fabrica-kit supports pluggable storage through the Data interface defined in router/routetable/routetable.go. The repository includes a Redis implementation in router/routetable/redis/redis.go, and developers can implement the interface for PostgreSQL, etcd, or other backends without modifying the routing logic.

How is the route key structured in fabrica-kit?

Route keys follow the deterministic format r_<name>_{<color>}_{<oid>} as implemented in router/routetable/routetable.go. This structure combines the table name, service color (logical group), and object ID to create a unique, computable location for each service instance without requiring a central registry.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →