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 includingBuildKey,Get, andBatchGetfor safe address resolution.ReNewalRouteTable: Extends read-only capabilities withRenewSelfandTTLmethods for entry renewal and TTL management.MasterRouteTable: The full write interface embeddingReNewalRouteTable, adding mutable operations likeSet,SetNxOrGet,GetSet, andGetExfor 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 underBuildKey(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.goprovide atomic write operations (Set,GetSet,SetNxOrGet) and TTL management for service registration. - Read-only route tables in
router/routetable/readonly.gooffer 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
Datainterface 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →