gorums icon indicating copy to clipboard operation
gorums copied to clipboard

Major Refactoring: Interceptor Architecture & Iterator-based Responses

Open meling opened this issue 2 months ago • 1 comments

This PR introduces a significant architectural shift for Gorums, moving towards a more flexible, interceptor-based design and adopting modern Go iterator patterns. These changes simplify the codebase, improve type safety, and offer better composability for users.

🚀 Key Changes

1. Client-Side Interceptor Architecture

The core request/response logic has been refactored to use a composable interceptor pattern, similar to connectrpc.

  • QuorumFunc & Interceptor: Replaces the rigid QuorumSpec interface. Users can now compose logic using Chain and standard interceptors.
  • Unified Logic: Multicast, Unicast, and QuorumCall now share a more unified underlying implementation.
  • Lazy Execution: Requests are now dispatched lazily when response iteration begins (or explicitly triggered), allowing for more flexible setup.

2. Iterator-Based Response Handling (Results[T])

We have adopted a fluent, iterator-based API for handling responses, replacing the previous hardcoded callback/QuorumSpec approach.

  • Results[T]: A new type alias for iter.Seq[NodeResponse[T]] that serves as the receiver for helper methods.

  • Fluent API: You can now chain methods for cleaner code:

    // Before (Quorum logic hidden in QuorumSpec)
    // replies, err := config.Read(ctx, req)
    
    // After (Explicit control)
    replies, err := config.Read(ctx, req).Majority()
    
  • Unified Node ID: The NodeResponse[T] struct now contains the NodeID.

3. Template Overhaul & Simplification

The protoc-gen-gorums templates have been significantly simplified.

  • Removed QuorumSpec Generation: The complex QuorumSpec interface generation has been removed. The runtime now handles this via generic QuorumCall implementations.
  • Reduced Code Size: Generated code is now smaller and relies more on the simplified Gorums runtime.

4. Correctable Call Refactoring

Correctable calls have been split into two distinct types to improve clarity and type safety:

  • Correctable: For unary correctable calls (one request, progressive responses).
  • CorrectableStream: For streaming correctable calls. This removes the ambiguous serverStream boolean toggle and simplifies the generated code.

⚠️ Breaking Changes

  • QuorumSpec Interface Removed: The generated QuorumSpec interface is gone. Custom quorum logic should now be implemented using the new QuorumFunc or Interceptor patterns, or by using the built-in aggregators (Majority, All, First).
  • New Response pattern: Calls that previously returned a single aggregated value (like (*Response, error)) now return a *Responses object, requiring a terminal method call (like .Majority()) or iteration to retrieve the result.

📝 Migration Guide

Migrating from QuorumSpec

Calls that relied on QuorumSpec validation now require explicit aggregation or iteration.

Old (Implicit QuorumSpec logic):

// Quorum logic was defined in a separate QSpec struct
resp, err := config.Read(ctx, req)
if err != nil { ... }

New (Explicit Aggregation):

// Use built-in aggregators for standard patterns
resp, err := config.Read(ctx, req).Majority()

// OR use custom iteration for complex logic
for resp := range config.Read(ctx, req).Seq() {
    // Process individual responses
    if complexCheck(resp) { ... }
}

meling avatar Dec 14 '25 14:12 meling

Here's the code health analysis summary for commits 691cd1b..2306fac. View details on DeepSource ↗.

Analysis Summary

AnalyzerStatusSummaryLink
DeepSource Go LogoGo✅ Success
🎯 6 occurences resolved
View Check ↗
DeepSource Shell LogoShell✅ SuccessView Check ↗

💡 If you’re a repository administrator, you can configure the quality gates from the settings.

deepsource-io[bot] avatar Dec 14 '25 14:12 deepsource-io[bot]