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

> Learn how Fabrica-Kit manages route tables with master and read-only configurations. Explore its layered interface, deterministic keys, and pluggable storage for service registration.

- Repository: [Pantheon/fabrica-kit](https://github.com/go-pantheon/fabrica-kit)
- Tags: deep-dive
- Published: 2026-03-02

---

**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`](https://github.com/go-pantheon/fabrica-kit/blob/main/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`](https://github.com/go-pantheon/fabrica-kit/blob/main/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`](https://github.com/go-pantheon/fabrica-kit/blob/main/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](https://github.com/go-pantheon/fabrica-kit/blob/main/router/routetable/master.go#L40-L47)).
- **`GetSet`**: Atomically retrieves the previous address while overwriting it with a new value ([master.go L30-L38](https://github.com/go-pantheon/fabrica-kit/blob/main/router/routetable/master.go#L30-L38)).
- **`SetNxOrGet`**: Implements idempotent registration by setting the entry only if absent, returning the existing value otherwise ([master.go L49-L57](https://github.com/go-pantheon/fabrica-kit/blob/main/router/routetable/master.go#L49-L57)).

### TTL Management and Self-Renewal

Master tables embed `renewalRouteTable` from [`router/routetable/renewal.go`](https://github.com/go-pantheon/fabrica-kit/blob/main/router/routetable/renewal.go) to handle TTL configuration and entry renewal:

```go
// 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](https://github.com/go-pantheon/fabrica-kit/blob/main/router/routetable/renewal.go#L55-L66)).

## Read-Only Route Table Configuration

### Query Operations for Service Discovery

The `readOnlyRouteTable` in [`router/routetable/readonly.go`](https://github.com/go-pantheon/fabrica-kit/blob/main/router/routetable/readonly.go) provides safe, non-mutable access for clients that need to resolve service addresses:

```go
// 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](https://github.com/go-pantheon/fabrica-kit/blob/main/router/routetable/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`](https://github.com/go-pantheon/fabrica-kit/blob/main/router/routetable/routetable.go):

```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`](https://github.com/go-pantheon/fabrica-kit/blob/main/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`](https://github.com/go-pantheon/fabrica-kit/blob/main/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`](https://github.com/go-pantheon/fabrica-kit/blob/main/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`](https://github.com/go-pantheon/fabrica-kit/blob/main/router/routetable/routetable.go). The repository includes a Redis implementation in [`router/routetable/redis/redis.go`](https://github.com/go-pantheon/fabrica-kit/blob/main/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`](https://github.com/go-pantheon/fabrica-kit/blob/main/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.