Skip to content

feat(grpc): Implement SummaryReader in gRPC storage adapter#8642

Merged
yurishkuro merged 7 commits into
jaegertracing:mainfrom
yurishkuro:feat/grpc-find-trace-summaries
May 27, 2026
Merged

feat(grpc): Implement SummaryReader in gRPC storage adapter#8642
yurishkuro merged 7 commits into
jaegertracing:mainfrom
yurishkuro:feat/grpc-find-trace-summaries

Conversation

@yurishkuro

@yurishkuro yurishkuro commented May 26, 2026

Copy link
Copy Markdown
Member

Summary

  • Handler.FindTraceSummaries in internal/storage/v2/grpc/handler.go forwards to the underlying tracestore.SummaryReader if the trace reader implements it, otherwise returns codes.Unimplemented. Existing remote storage plugins are unaffected — UnimplementedTraceReaderServer covers them automatically.
  • TraceReader.FindTraceSummaries in internal/storage/v2/grpc/tracereader.go implements tracestore.SummaryReader as a plain iterator (same signature as FindTraces, no top-level error). codes.Unimplemented from the server arrives via the first Recv() (gRPC streaming behavior) and is yielded as errors.ErrUnsupported. QueryService detects this on the first iterator yield and falls back to computeSummaries transparently.
  • SummaryReader.FindTraceSummaries interface simplified: returns iter.Seq2[[]TraceSummary, error] — no top-level error, matching FindTraces.
  • FindTraceSummaries added to capabilities.GRPC() skip list — the gRPC e2e test uses a memory backend that doesn't implement SummaryReader, so the test is skipped until memory implements it.
  • jptrace.TimeToUnixNano / UnixNanoToTime shared utilities added; three duplicate inline implementations removed.
  • ADR-010: all DECISION sections and Milestone 4 marked ✅; PR D marked done; PR F row removed (already delivered in jaeger-ui).

Test plan

  • go test ./internal/storage/v2/grpc/... — new handler and client unit tests pass
  • go test ./internal/storage/integration/... — integration capabilities compile
  • make lint — 0 issues
  • go test ./internal/jptrace/... — new timestamp utility tests pass

🤖 Generated with Claude Code

Handler.FindTraceSummaries forwards to the underlying
tracestore.SummaryReader when available; returns codes.Unimplemented
otherwise (the default from UnimplementedTraceReaderServer).

TraceReader.FindTraceSummaries implements tracestore.SummaryReader
on the client side. The stream is primed eagerly: the first Recv is
called before handing back an iterator, so a codes.Unimplemented
response is surfaced as a direct errors.ErrUnsupported-wrapped error
rather than appearing inside the iterator. QueryService picks up the
new implementation automatically via the existing findSummaryReader
chain-walker.

Remove FindTraceSummaries from capabilities.GRPC() skip list so that
the gRPC integration test exercises the full round-trip.

Update ADR-010: mark all DECISION sections and Milestone 4 as done,
mark PR D as done, remove completed PR F row.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
Copilot AI review requested due to automatic review settings May 26, 2026 04:06
@yurishkuro yurishkuro requested a review from a team as a code owner May 26, 2026 04:06
@dosubot dosubot Bot added area/storage go Pull requests that update go code labels May 26, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends Jaeger’s storage-v2 gRPC remote storage adapter to support the optional tracestore.SummaryReader capability, enabling FindTraceSummaries to work end-to-end over gRPC and allowing QueryService to fall back to local summary computation when the remote backend does not implement it.

Changes:

  • Add FindTraceSummaries support to the gRPC storage client (TraceReader) with eager stream priming to surface UNIMPLEMENTED as a direct errors.ErrUnsupported error.
  • Add FindTraceSummaries support to the gRPC storage server (Handler) by forwarding to an underlying tracestore.SummaryReader when available.
  • Enable the gRPC integration capability test for FindTraceSummaries by removing it from the gRPC skip list; update ADR-010 milestone/status text.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
internal/storage/v2/grpc/tracereader.go Implements tracestore.SummaryReader on the gRPC client adapter, including eager stream priming and proto→model conversion.
internal/storage/v2/grpc/tracereader_test.go Adds unit tests covering success, stream error, and UNIMPLEMENTED handling for FindTraceSummaries.
internal/storage/v2/grpc/handler.go Adds gRPC server-side FindTraceSummaries RPC that delegates to an underlying SummaryReader.
internal/storage/v2/grpc/handler_test.go Adds unit tests for handler delegation, not-implemented behavior, iterator error propagation, and send errors.
internal/storage/integration/capabilities/capabilities.go Removes the gRPC skip list entry so integration tests exercise FindTraceSummaries over gRPC.
docs/adr/010-trace-summary-api.md Marks decisions/milestone progress as complete for the remote storage adapter work and updates status text.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/storage/v2/grpc/handler.go Outdated
Comment thread internal/storage/v2/grpc/handler.go Outdated
@codecov

codecov Bot commented May 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.60%. Comparing base (a6ee2e9) to head (c3de257).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8642      +/-   ##
==========================================
+ Coverage   96.56%   96.60%   +0.03%     
==========================================
  Files         334      334              
  Lines       17721    17803      +82     
==========================================
+ Hits        17112    17198      +86     
+ Misses        456      455       -1     
+ Partials      153      150       -3     
Flag Coverage Δ
badger_direct 8.86% <0.00%> (-0.08%) ⬇️
badger_e2e 1.03% <0.00%> (-0.01%) ⬇️
cassandra-4.x-direct-manual 14.42% <0.00%> (-0.13%) ⬇️
cassandra-4.x-e2e-auto 1.02% <0.00%> (-0.01%) ⬇️
cassandra-4.x-e2e-manual 1.02% <0.00%> (-0.01%) ⬇️
cassandra-5.x-direct-manual 14.42% <0.00%> (-0.13%) ⬇️
cassandra-5.x-e2e-auto 1.02% <0.00%> (-0.01%) ⬇️
cassandra-5.x-e2e-manual 1.02% <0.00%> (-0.01%) ⬇️
clickhouse-direct 8.89% <0.00%> (-0.08%) ⬇️
clickhouse-e2e 1.17% <2.40%> (+0.01%) ⬆️
elasticsearch-6.x-direct 16.72% <0.00%> (-0.15%) ⬇️
elasticsearch-7.x-direct 16.76% <0.00%> (-0.15%) ⬇️
elasticsearch-8.x-direct 16.90% <0.00%> (-0.15%) ⬇️
elasticsearch-8.x-e2e 1.03% <0.00%> (-0.01%) ⬇️
elasticsearch-9.x-e2e 1.03% <0.00%> (-0.01%) ⬇️
grpc_direct 7.83% <0.00%> (-0.07%) ⬇️
grpc_e2e 1.05% <2.40%> (+0.01%) ⬆️
kafka-3.x-v2 1.03% <0.00%> (-0.01%) ⬇️
memory_v2 1.05% <2.40%> (+0.01%) ⬆️
opensearch-1.x-direct 16.80% <0.00%> (-0.15%) ⬇️
opensearch-2.x-direct 16.80% <0.00%> (-0.15%) ⬇️
opensearch-2.x-e2e 1.03% <0.00%> (-0.01%) ⬇️
opensearch-3.x-e2e 1.03% <0.00%> (-0.01%) ⬇️
query 1.05% <2.40%> (+0.01%) ⬆️
tailsampling-processor 0.54% <0.00%> (-0.01%) ⬇️
unittests 94.92% <100.00%> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@yurishkuro yurishkuro added the changelog:experimental Change to an experimental part of the code label May 26, 2026
Comment thread internal/storage/v2/grpc/tracereader.go Outdated
yurishkuro and others added 2 commits May 26, 2026 00:33
…PC e2e

- Clarify stream-priming comment: gRPC delivers RPC-level errors via
  the first Recv(), so priming is needed to surface ErrUnsupported as
  a direct return for QueryService fallback.
- Add FindTraceSummaries to GRPC() skip list: the test backend (memory)
  does not implement SummaryReader, so the test times out without the skip.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
Add jptrace.TimeToUnixNano and jptrace.UnixNanoToTime to replace three
duplicate inline implementations of time↔uint64 conversion across
handler.go, tracereader.go, and integration/trace_reader.go.
TimeToUnixNano returns 0 for zero or pre-epoch times to match the proto3
default (field omitted), avoiding uint64 wrap-around on negative values.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
@github-actions

github-actions Bot commented May 26, 2026

Copy link
Copy Markdown

CI Summary Report

Metrics Comparison

⚠️ 17 metric change(s) detected (informational)

View changed metrics

For label-level diff details, open the CI run and expand the "Compare metrics and generate summary" step logs.

metrics_snapshot_grpc_e2e⬇️ download diff
1 added

  • rpc_client_call_duration

Code Coverage

✅ Coverage 97.3% (baseline 97.3%)

➡️ View CI run | View publish logs
2026-05-27 00:31:11 UTC

…iterator

Remove the top-level error return from SummaryReader.FindTraceSummaries,
aligning it with FindTraces. ErrUnsupported is now yielded as the first
iterator error instead of returned directly.

QueryService.FindTraceSummaries wraps the iterator and falls back to
computeSummaries on the first ErrUnsupported error. This removes the
need for stream priming in grpc.TraceReader and simplifies the overall
design.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
Copilot AI review requested due to automatic review settings May 26, 2026 04:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 16 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • internal/storage/v2/api/tracestore/mocks/mocks.go: Language not supported
Comments suppressed due to low confidence (2)

internal/storage/integration/capabilities/capabilities.go:50

  • PR description says FindTraceSummaries was removed from the gRPC capabilities skip list so the integration test exercises the full round-trip, but Capabilities.GRPC() still skips FindTraceSummaries here (and the comment explains why). Either the PR description is out of date, or this skipList should be updated to reflect the new behavior.
// GRPC returns the capabilities for the gRPC remote storage backend.
// FindTraceSummaries is skipped because it depends on the backing store
// implementing tracestore.SummaryReader; the test backend (memory) does not yet.
func GRPC() Capabilities {
	return Capabilities{
		skipList: []string{FindTraceSummariesTest},
	}

cmd/jaeger/internal/integration/trace_reader.go:185

  • In this server-streaming RPC, codes.Unimplemented can be delivered via stream.Recv() (not just the initial FindTraceSummaries call). The loop currently yields the raw error on Recv() failures, which means an UNIMPLEMENTED response won’t be translated to errors.ErrUnsupported and callers won’t trigger the intended fallback. Consider mapping status.Code(err) == codes.Unimplemented to a yielded errors.ErrUnsupported here too (mirroring internal/storage/v2/grpc/tracereader.go).
		for {
			resp, err := stream.Recv()
			if errors.Is(err, io.EOF) {
				return
			}
			if err != nil {
				yield(nil, err)
				return
			}

Comment thread docs/adr/010-trace-summary-api.md Outdated
yurishkuro and others added 2 commits May 26, 2026 00:58
- SummaryReader.FindTraceSummaries now returns iter.Seq2 (no top-level error)
- ErrUnsupported is yielded as the first iterator error, not returned directly
- QueryService wraps the iterator and falls back on first ErrUnsupported yield
- Section 6 notes that gRPC RPC-level errors arrive via Recv(), not the initial call
- Update Milestone 4 items and PR table row D accordingly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
- tracereader: add GRPCClientError and YieldStopsIteration tests; remove
  dead code (initial-call codes.Unimplemented branch, which gRPC never
  triggers for server-streaming RPCs)
- service: add YieldStopsIteration tests for native path and
  ErrUnsupported fallback path

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Yuri Shkuro <github@ysh.us>
Copilot AI review requested due to automatic review settings May 26, 2026 05:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 16 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • internal/storage/v2/api/tracestore/mocks/mocks.go: Language not supported
Comments suppressed due to low confidence (1)

cmd/jaeger/internal/integration/trace_reader.go:185

  • In the api_v3 integration traceReader.FindTraceSummaries iterator, Unimplemented is only translated to errors.ErrUnsupported when returned from the initial FindTraceSummaries(...) call. For server-streaming RPCs, gRPC-Go can deliver RPC-level errors (including codes.Unimplemented) via stream.Recv(), so the current Recv() error branch would yield a raw gRPC status error instead of ErrUnsupported (preventing any caller-side fallback/skip logic based on errors.Is(err, errors.ErrUnsupported)). Consider also checking status.Code(err)==codes.Unimplemented in the Recv() error path and yielding an error that wraps errors.ErrUnsupported.
		for {
			resp, err := stream.Recv()
			if errors.Is(err, io.EOF) {
				return
			}
			if err != nil {
				yield(nil, err)
				return
			}

Comment thread internal/storage/v2/grpc/tracereader.go Outdated
Comment thread internal/jptrace/timestamp.go
Signed-off-by: Yuri Shkuro <github@ysh.us>
@yurishkuro yurishkuro merged commit a50c124 into jaegertracing:main May 27, 2026
73 checks passed
@yurishkuro yurishkuro deleted the feat/grpc-find-trace-summaries branch May 27, 2026 00:33
vic-comm pushed a commit to vic-comm/jaeger that referenced this pull request Jun 11, 2026
…acing#8642)

## Summary

- `Handler.FindTraceSummaries` in `internal/storage/v2/grpc/handler.go`
forwards to the underlying `tracestore.SummaryReader` if the trace
reader implements it, otherwise returns `codes.Unimplemented`. Existing
remote storage plugins are unaffected — `UnimplementedTraceReaderServer`
covers them automatically.
- `TraceReader.FindTraceSummaries` in
`internal/storage/v2/grpc/tracereader.go` implements
`tracestore.SummaryReader` as a **plain iterator** (same signature as
`FindTraces`, no top-level error). `codes.Unimplemented` from the server
arrives via the first `Recv()` (gRPC streaming behavior) and is yielded
as `errors.ErrUnsupported`. `QueryService` detects this on the first
iterator yield and falls back to `computeSummaries` transparently.
- `SummaryReader.FindTraceSummaries` interface simplified: returns
`iter.Seq2[[]TraceSummary, error]` — no top-level error, matching
`FindTraces`.
- `FindTraceSummaries` added to `capabilities.GRPC()` skip list — the
gRPC e2e test uses a memory backend that doesn't implement
`SummaryReader`, so the test is skipped until memory implements it.
- `jptrace.TimeToUnixNano` / `UnixNanoToTime` shared utilities added;
three duplicate inline implementations removed.
- ADR-010: all DECISION sections and Milestone 4 marked ✅; PR D marked
done; PR F row removed (already delivered in jaeger-ui).

## Test plan

- [x] `go test ./internal/storage/v2/grpc/...` — new handler and client
unit tests pass
- [x] `go test ./internal/storage/integration/...` — integration
capabilities compile
- [x] `make lint` — 0 issues
- [x] `go test ./internal/jptrace/...` — new timestamp utility tests
pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Signed-off-by: Yuri Shkuro <github@ysh.us>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Victor Chidera Obiezue <obiezuechidera@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/storage changelog:experimental Change to an experimental part of the code go Pull requests that update go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants