What Is Trace Context Tracking in CCX? A Technical Deep Dive
Trace context tracking in CCX is a mechanism that maintains "trace-affinity" mappings between users and API channels, enabling subsequent requests from the same conversation to reuse previously successful channels with 30-minute TTL expiration.
CCX implements intelligent request routing by preserving channel preferences per user and request type, ensuring low-latency retries and consistent performance across multi-channel AI deployments. This article examines the implementation details found in the BenedictKing/ccx repository, explaining how the TraceAffinityManager and ChannelScheduler collaborate to optimize API request distribution.
Core Components of Trace Context Tracking
TraceAffinityManager
The TraceAffinityManager defined in backend-go/internal/session/trace_affinity.go serves as the persistence layer for affinity data. It maintains a thread-safe map that stores channel preferences using composite keys formatted as <kind>:<userID>.
The manager handles four critical responsibilities:
- Mapping storage: Associates users with their preferred channel indices per request type (messages, responses, gemini, chat, images)
- TTL enforcement: Automatically expires entries after 30 minutes of inactivity
- Periodic cleanup: Runs a
cleanupLoopevery 5 minutes to purge stale records and prevent memory leaks - Query interface: Provides
GetPreferredChannel,SetPreferredChannel, andUpdateLastUsedmethods for read/write operations
ChannelScheduler Integration
The ChannelScheduler in backend-go/internal/scheduler/channel_scheduler.go consumes the affinity data during the routing decision process. During initialization in backend-go/main.go (lines 29-35), the scheduler receives a singleton instance of TraceAffinityManager, ensuring consistent state across all request handling goroutines.
How Trace Affinity Works
Data Structure and Storage
Each affinity record uses the TraceAffinity struct:
type TraceAffinity struct {
ChannelIndex int // Selected channel index in the upstream pool
LastUsedAt time.Time // Last access timestamp for TTL calculation
}
The manager stores these in a map[string]*TraceAffinity where the key combines the channel kind and user identifier. This design allows separate affinity tracking across different API endpoints while maintaining user isolation.
TTL and Cleanup Mechanism
The system implements automatic resource reclamation through configurable expiration:
- Default TTL: 30 minutes (
ttl: 30 * time.MinuteinNewTraceAffinityManager) - Cleanup interval: 5 minutes between garbage collection cycles
- Thread safety: All map operations use mutex locking to prevent race conditions during concurrent API requests
When UpdateTraceAffinity is called, the manager resets the LastUsedAt timestamp, extending the affinity window for active conversations.
The Selection Flow
During channel selection, SelectChannel evaluates trace affinity as a fallback mechanism. The decision logic in channel_scheduler.go follows this priority order:
- Manual override: X-Channel headers specifying explicit channels
- Promotional channels: High-priority routes that bypass health checks
- Trace affinity: Reuse previous channel if promotional routes fail or are unavailable
- Priority scheduling: Configured
priorityvalues from channel definitions - Fallback selection: Channels with lowest failure rates
The affinity check occurs only when:
if userID != "" {
compositeKey := string(kind) + ":" + userID
if preferredIdx, ok := s.traceAffinity.GetPreferredChannel(compositeKey); ok {
// Verify channel health and availability before returning
return &SelectionResult{
Upstream: upstream,
ChannelIndex: preferredIdx,
Reason: "trace_affinity",
}, nil
}
}
The scheduler validates that the preferred channel remains active, healthy (no circuit breaker trips), and represents the best available option before committing to the affinity route.
Recording Successful Channels
After processing a successful request, business handlers invoke the affinity recording methods:
func (s *ChannelScheduler) SetTraceAffinity(userID string, channelIndex int, kind ChannelKind) {
if userID != "" {
compositeKey := string(kind) + ":" + userID
s.traceAffinity.SetPreferredChannel(compositeKey, channelIndex)
}
}
For ongoing conversation threads, handlers call UpdateTraceAffinity at request start to refresh the TTL timer:
func (s *ChannelScheduler) UpdateTraceAffinity(userID string, kind ChannelKind) {
if userID != "" {
compositeKey := string(kind) + ":" + userID
s.traceAffinity.UpdateLastUsed(compositeKey)
}
}
These invocations typically occur in handlers such as messages.Handler and responses.Handler, ensuring that multi-turn conversations maintain channel consistency.
Monitoring and Debugging
CCX exposes affinity statistics through the dashboard API endpoint /api/messages/channels/dashboard. The response includes:
{
"traceAffinityCount": 12,
"traceAffinityTTL": "30m0s"
}
The implementation resides in channel_scheduler.go via GetTraceAffinityManager and the HTTP handler in backend-go/internal/handlers/channel_dashboard.go. This visibility helps operators identify how many active affinity relationships exist in the system.
Practical Implementation Examples
Setting Affinity After Successful Requests
Business logic handlers update affinity records following successful API calls:
// After processing a successful message request
func afterSuccess(ctx context.Context, userID string, kind scheduler.ChannelKind, chIdx int) {
// scheduler is the injected *ChannelScheduler instance from main.go
scheduler.SetTraceAffinity(userID, chIdx, kind)
scheduler.UpdateTraceAffinity(userID, kind) // Optional TTL renewal
}
Route Request With Affinity Check
The routing layer automatically evaluates affinity during channel selection:
func routeRequest(userID string, kind scheduler.ChannelKind) (*scheduler.SelectionResult, error) {
failedChannels := make(map[int]bool)
result, err := scheduler.SelectChannel(
context.Background(),
userID,
failedChannels,
kind,
"", // model parameter
"", // routePrefix
"", // channelName
)
if err != nil {
return nil, err
}
// Check if affinity routing was applied
if result.Reason == "trace_affinity" {
log.Printf("Routed via trace affinity to channel %d", result.ChannelIndex)
}
return result, nil
}
Why Trace Context Tracking Matters
Latency reduction: Subsequent requests bypass expensive health checks and priority calculations by reusing validated channels.
Success rate optimization: In multi-channel environments, specific channels often perform better for particular user contexts (token limits, model preferences). Affinity preserves these successful pairings.
Operational visibility: Requests routed via affinity include Reason: "trace_affinity" in logs and metrics, enabling rapid identification of traffic distribution patterns.
User experience consistency: Maintaining the same channel across conversation turns preserves context-specific optimizations and caching benefits.
Summary
- TraceAffinityManager in
trace_affinity.gomaintains user-to-channel mappings with 30-minute TTL expiration and 5-minute cleanup cycles. - ChannelScheduler evaluates affinity as the third priority tier, after manual overrides and promotional channels but before generic priority scheduling.
- Composite keys using
<kind>:<userID>format enable separate affinity tracking per API endpoint type (messages, chat, images). - Recording methods
SetTraceAffinityandUpdateTraceAffinityare invoked by business handlers after successful request processing. - Dashboard endpoint
/api/messages/channels/dashboardexposes real-time affinity statistics for operational monitoring.
Frequently Asked Questions
How long does CCX retain trace affinity data?
CCX retains trace affinity records for 30 minutes by default. The TraceAffinityManager initializes with ttl: 30 * time.Minute and runs a cleanup loop every 5 minutes to purge expired entries. Active requests refresh this timer via UpdateLastUsed, keeping the affinity window open for ongoing conversations.
When does the scheduler ignore trace affinity recommendations?
The scheduler bypasses trace affinity when: (1) no userID is present in the request, (2) the preferred channel has become unhealthy or inactive, (3) a higher-priority channel (manual override or promotional) is available, or (4) the affinity record has expired past the TTL threshold. The system always validates channel health before committing to an affinity route.
Can operators view current trace affinity mappings?
Yes. CCX exposes affinity statistics through the /api/messages/channels/dashboard endpoint, which returns the current count of active affinity relationships and the configured TTL duration. The underlying implementation in channel_dashboard.go and GetTraceAffinityManager provides this visibility without exposing sensitive user mapping details.
What happens when a preferred channel fails during affinity routing?
If an affinity-preferred channel fails health checks during SelectChannel, the scheduler automatically falls back to the standard priority-based selection logic. The failed channel is marked in the failedChannels map, and the request proceeds to the next available option. This ensures that affinity preferences do not compromise request success rates when channels degrade.
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 →