# Integrating Fabrica-Util with Roma, Janus, Lares, and Senate: A Complete Guide

> Integrate fabrica-util with Roma Janus Lares and Senate. Learn essential considerations for unified runtime behavior across the go-pantheon ecosystem. Master initialization order modularity and version alignment.

- Repository: [Pantheon/fabrica-util](https://github.com/go-pantheon/fabrica-util)
- Tags: how-to-guide
- Published: 2026-03-02

---

**Fabrica-Util provides the foundational utility library that unifies runtime behavior across the go-pantheon ecosystem, requiring careful attention to initialization order, package modularity, and version alignment when integrating with Roma, Janus, Lares, and Senate.**

Fabrica-Util serves as the core utility library for the go-pantheon microservices architecture, providing shared primitives for time handling, concurrency, cryptography, and distributed ID generation. When integrating this library with Roma (game-logic), Janus (gateway), Lares (account), and Senate (admin) services, developers must follow specific architectural contracts to ensure consistent behavior across the cluster. This guide examines the source code implementation to provide practical integration patterns for each component.

## Package Modularity and Import Patterns

Fabrica-Util organizes functionality into discrete, well-typed packages that each service imports selectively. This modular design prevents bloat while maintaining unified runtime behavior across the go-pantheon ecosystem.

### Time Handling with xtime

The `xtime` package provides timezone-aware timestamp operations and period calculations. Roma relies on this for deterministic daily and weekly game resets, while Janus uses it for request timestamp normalization. Lares leverages `xtime` for time-based token expiration, and Senate schedules maintenance windows using these utilities.

Import path: `github.com/go-pantheon/fabrica-util/xtime`

### Concurrency Primitives with xsync

The `xsync` package contains delayers, futures, and goroutine lifecycle helpers. Janus manages per-connection timeouts using `NewDelayer`, Roma spawns background workers with `Go` helpers, Senate runs periodic jobs, and Lares implements cancellable async flows. The `Future` type supports context-based cancellation via `GetWithContext` as implemented in [`xsync/future.go`](https://github.com/go-pantheon/fabrica-util/blob/main/xsync/future.go)【L58-L70】.

Import path: `github.com/go-pantheon/fabrica-util/xsync`

### Distributed Identity with xid

The `xid` package generates zone-aware identifiers using HashID encoding. All services must reference the same player identifier format, with zone bits guaranteeing global uniqueness across data centers. The `BuildUID` function in [`xid/id.go`](https://github.com/go-pantheon/fabrica-util/blob/main/xid/id.go)【L58-L79】 constructs these identifiers, while `EncodeID` and `DecodeID` handle obfuscation.

Import path: `github.com/go-pantheon/fabrica-util/xid`

### Cryptographic Utilities

The `security` hierarchy provides AES-GCM, RSA, ECDH, and X.509 handling. Lares encrypts authentication tokens, Roma encrypts persisted game state snapshots, Janus secures payloads, and Senate protects configuration files. The `security/aes` package validates key sizes during `NewAESCipher` initialization to ensure cross-service compatibility【L20-L27】.

Import path: `github.com/go-pantheon/fabrica-util/security/aes`

### Data Structures for Distributed Systems

Specialized packages support distributed architectures:

- **consistenthash**: Provides the hash ring implementation used by Roma for player sharding
- **bloom**: Supplies probabilistic filters for Janus anti-spam detection
- **bitmap**: Offers compact bit-set storage for Senate flag management

## Initialization Order and Configuration

Most Fabrica-Util packages require explicit initialization before use. Skipping these steps causes fallback to safe defaults (such as UTC for time), which may produce inconsistent results across the cluster.

### Critical Initialization Sequence

1. **xtime.Init**: Must execute first in any binary handling timestamps. The function in [`xtime/time.go`](https://github.com/go-pantheon/fabrica-util/blob/main/xtime/time.go)【L22-L53】 parses configuration, loads the location atomically, and falls back to default locale settings. Roma, Janus, and Lares must all call this during startup.

2. **xid Configuration**: While the package initializes automatically via `init()` blocks, services must agree on identical `zoneBit` and `zoneSlotBit` layouts to ensure binary-compatible ID generation.

3. **Security Setup**: Cryptographic packages like `security/aes` require explicit cipher creation through `NewAESCipher`, which validates key sizes for cross-service compatibility.

## Error Handling and Context Propagation

All utilities integrate with the project-wide `errors` wrapper, preserving stack traces and supporting service-wide error policies such as gRPC status conversion. Concurrency primitives expose cancellation through Go's context package.

The `Future` type provides `GetWithContext` for deadline propagation, allowing services to cancel asynchronous operations without additional boilerplate【L58-L70】. Similarly, the `Delayer` supports explicit cancellation methods alongside its timer-based `Wait()` channel.

## Thread Safety and Performance Characteristics

Fabrica-Util implements lock-free and low-contention patterns suitable for high-frequency operations:

- **Atomic location storage** in `xtime` guarantees lock-free reads after initialization using atomic value storage【L12-L15】
- **Delayer** uses a single `time.Timer` protected by an RW-mutex, with buffered channels to prevent caller blocking【L45-L50】【L71-L78】
- **Future** and **Then** are fully generic, avoiding unnecessary allocations suitable for Roma's game loops

## Version Compatibility and Dependency Management

Fabrica-Util targets **Go 1.24+** across all packages. Services must align `go.mod` dependencies to the same `vX.Y.Z` tag; mismatched versions can break binary-compatible `hashid` layouts used by `xid`.

The repository enforces a strict license policy permitting only MIT, Apache-2.0, BSD, ISC, and MPL-2.0 dependencies, preventing legal complications when shipping services【L13-L22】.

## Practical Integration Examples

### Initializing Time Utilities in Roma and Janus

```go
import (
	"log"

	"github.com/go-pantheon/fabrica-util/xtime"
)

func initTime() {
	if err := xtime.Init(xtime.Config{
		Language: "en",
		Timezone: "Asia/Shanghai",
	}); err != nil {
		log.Fatalf("time init failed: %v", err)
	}
}

```

This initialization pattern appears in [`xtime/time.go`](https://github.com/go-pantheon/fabrica-util/blob/main/xtime/time.go)【L22-L53】, loading the timezone location atomically for subsequent operations.

### Generating Zone-Based IDs for Lares and Roma

```go
import (
	"fmt"

	"github.com/go-pantheon/fabrica-util/xid"
)

func playerIDExample() {
	uid, _ := xid.BuildUID(12345, 3)          // zone 3
	enc, _ := xid.EncodeID(uid)               // hashid string
	fmt.Println("Encoded:", enc)

	dec, _ := xid.DecodeID(enc)
	gameID, zone := xid.SplitUID(dec)
	fmt.Printf("Decoded gameID=%d zone=%d\n", gameID, zone)
}

```

The [`xid/id.go`](https://github.com/go-pantheon/fabrica-util/blob/main/xid/id.go) implementation【L58-L79】 provides zone-aware construction and HashID encoding.

### Managing Connection Timeouts in Janus

```go
import (
	"fmt"
	"time"

	"github.com/go-pantheon/fabrica-util/xsync"
)

func connTimeoutDemo() {
	d := xsync.NewDelayer()
	expireAt := time.Now().Add(5 * time.Second)
	d.SetExpiryTime(expireAt)

	fmt.Println("Waiting for expiry…")
	<-d.Wait() // blocks until timer fires
	fmt.Println("Connection timed out")
}

```

The `Delayer` implementation in [`xsync/delayer.go`](https://github.com/go-pantheon/fabrica-util/blob/main/xsync/delayer.go) uses buffered channels and RW-mutex protection【L45-L50】【L71-L78】.

### Chaining Asynchronous Operations in Roma

```go
import (
	"context"
	"fmt"
	"time"

	"github.com/go-pantheon/fabrica-util/xsync"
)

func asyncChain() {
	f := xsync.NewFuture[int]()
	go func() {
		// simulate work
		f.Complete(42, nil)
	}()

	// Transform the result
	f2 := xsync.Then[int, string](f, func(v int) (string, error) {
		return fmt.Sprintf("value=%d", v), nil
	})

	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()
	s, err := f2.GetWithContext(ctx)
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Println("final:", s) // -> "final: value=42"
}

```

The `Then` function and context-aware retrieval appear in [`xsync/future.go`](https://github.com/go-pantheon/fabrica-util/blob/main/xsync/future.go)【L58-L70】【L93-L112】.

### Encrypting Sensitive Data Across Services

```go
import (
	"fmt"

	"github.com/go-pantheon/fabrica-util/security/aes"
)

func encryptDemo() {
	key := []byte("0123456789abcdef0123456789abcdef") // 32-byte key
	c, _ := aes.NewAESCipher(key)

	plain := []byte("super-secret")
	ciphertext, _ := c.Encrypt(plain)

	fmt.Printf("cipher: %x\n", ciphertext)

	dec, _ := c.Decrypt(ciphertext)
	fmt.Println("decrypted:", string(dec))
}

```

The AES-GCM implementation in [`security/aes/aes.go`](https://github.com/go-pantheon/fabrica-util/blob/main/security/aes/aes.go) validates key sizes during initialization【L20-L38】.

## Key Source Files and Architecture

| File | Package | Role |
|------|---------|------|
| [`xtime/time.go`](https://github.com/go-pantheon/fabrica-util/blob/main/xtime/time.go) | `xtime` | Timezone handling and atomic location storage |
| [`xsync/delayer.go`](https://github.com/go-pantheon/fabrica-util/blob/main/xsync/delayer.go) | `xsync` | Timer-based expiry with RW-mutex protection |
| [`xsync/future.go`](https://github.com/go-pantheon/fabrica-util/blob/main/xsync/future.go) | `xsync` | Generic async results with context cancellation |
| [`xid/id.go`](https://github.com/go-pantheon/fabrica-util/blob/main/xid/id.go) | `xid` | Zone-aware ID construction and HashID encoding |
| [`security/aes/aes.go`](https://github.com/go-pantheon/fabrica-util/blob/main/security/aes/aes.go) | `security/aes` | AES-GCM encryption with PKCS7 padding |
| `consistenthash/*` | `consistenthash` | Distributed hash ring for Roma sharding |
| `bloom/*` | `bloom` | Probabilistic filters for Janus spam detection |
| `bitmap/*` | `bitmap` | Compact bit-sets for Senate flag storage |

## Summary

- **Initialize `xtime` first**: Call `xtime.Init` before any timestamp operations to ensure timezone consistency across Roma, Janus, and Lares
- **Align zone configurations**: Ensure identical `zoneBit` layouts in `xid` across all services to maintain ID compatibility
- **Use context propagation**: Leverage `GetWithContext` in `xsync` primitives to respect request deadlines without boilerplate
- **Verify Go versions**: Target Go 1.24+ and align Fabrica-Util versions across all services to prevent HashID incompatibilities
- **Respect thread-safety**: Rely on atomic operations in `xtime` and buffered channels in `Delayer` for high-concurrency scenarios

## Frequently Asked Questions

### What happens if xtime.Init is not called before using time functions?

Functions will fall back to safe defaults such as UTC, but this produces inconsistent results across the cluster. According to the implementation in [`xtime/time.go`](https://github.com/go-pantheon/fabrica-util/blob/main/xtime/time.go), the `Init` function loads the timezone location atomically; without it, services may calculate different daily reset times or token expirations.

### How do I ensure ID compatibility between different go-pantheon services?

All services must use the same `zoneBit` and `zoneSlotBit` configuration when calling `xid` functions. The `BuildUID` and `DecodeID` functions in [`xid/id.go`](https://github.com/go-pantheon/fabrica-util/blob/main/xid/id.go) rely on these bit layouts; mismatched configurations between Roma and Lares will cause player ID collisions or decoding failures.

### Is Fabrica-Util thread-safe for high-concurrency scenarios?

Yes. The library uses atomic value storage for timezone locations in `xtime`, RW-mutexes for the `Delayer` timer state, and lock-free patterns in `Future` implementations. These designs support high-frequency operations in Roma's game loops and Janus's connection handling without contention.

### What Go version is required to use Fabrica-Util?

Fabrica-Util targets **Go 1.24+** across all packages. The repository enforces this requirement to utilize modern language features and maintain compatibility. Services must update their `go.mod` files accordingly, as older versions may not support the generic implementations in `xsync` or the atomic patterns in `xtime`.