Background
Node.Latency() maintains a single exponential moving average per node, shared across all RPC types. This is sufficient for coarse node ranking but, becomes misleading when different RPCs have substantially different server-side processing times — the estimate conflates network latency with compute time and provides no per-operation breakdown.
A user-space workaround (measuring around node.MyRPC() calls and feeding a custom SortBy closure) is impractical because the normal call site is cfg.MyRPC(), not a per-node call. There is no clean hook for users to instrument at the right level without bypassing the configuration abstraction.
Proposed change
Add integrated per-RPC latency tracking at the code-generation layer so that each generated RPC method records its own moving average alongside the existing node-wide average. Concretely:
- Extend Node (or a new NodeStats struct) with a per-RPC latency map, keyed by RPC method name or a generated constant.
- The generated quorum-call and unicast stubs measure elapsed time per node response and update the per-RPC map, using the same EWMA approach as the current node-wide measurement.
- Expose the latency via the
NodeResponse type, which could be accessed as part of the ResponseSeq or Responses types.
- Another (less attractive) alternative is to expose a Node.LatencyFor(rpc string) time.Duration accessor (or a typed variant via generated code) so that SortBy closures can read per-RPC estimates.
- SortBy(gorums.Latency) continues to use the node-wide estimate; per-RPC ordering requires a user-supplied closure.
Acceptance criteria
- Per-RPC estimates are updated automatically with no changes required at call sites.
- Unmeasured RPCs return a sentinel (negative duration) consistent with the existing node-wide convention, so SortBy closures can handle the cold-start case uniformly.
- The existing Node.Latency() behavior and gorums.Latency comparator are unchanged.
- The user guide "Measurement Limits" section is updated to note that per-RPC tracking is available and link to the relevant accessor.
Background
Node.Latency() maintains a single exponential moving average per node, shared across all RPC types. This is sufficient for coarse node ranking but, becomes misleading when different RPCs have substantially different server-side processing times — the estimate conflates network latency with compute time and provides no per-operation breakdown.
A user-space workaround (measuring around node.MyRPC() calls and feeding a custom SortBy closure) is impractical because the normal call site is cfg.MyRPC(), not a per-node call. There is no clean hook for users to instrument at the right level without bypassing the configuration abstraction.
Proposed change
Add integrated per-RPC latency tracking at the code-generation layer so that each generated RPC method records its own moving average alongside the existing node-wide average. Concretely:
NodeResponsetype, which could be accessed as part of theResponseSeqorResponsestypes.Acceptance criteria