diff --git a/CHANGELOG.md b/CHANGELOG.md index 20212849..9bcabfee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ **Internal**: - Fix flamegraph endpoint span nesting. ([#677](https://github.com/getsentry/vroom/pull/677)) +- More robust concurrency structure for flamegraph generation. ([#678](https://github.com/getsentry/vroom/pull/678)) ## 26.9.0 diff --git a/internal/flamegraph/flamegraph.go b/internal/flamegraph/flamegraph.go index 809117f0..bc789a9f 100644 --- a/internal/flamegraph/flamegraph.go +++ b/internal/flamegraph/flamegraph.go @@ -371,13 +371,16 @@ func GetFlamegraphFromCandidates( hub := sentry.GetHubFromContext(ctx) results := make(chan storageutil.ReadJobResult) - defer close(results) + dispatchDone := make(chan struct{}) go func() { dispatchSpan := sentry.StartSpan(ctx, "dispatch candidates") dispatchSpan.SetData("transaction_candidates", len(transactionProfileCandidates)) dispatchSpan.SetData("continuous_candidates", len(continuousProfileCandidates)) - defer dispatchSpan.Finish() + defer func() { + dispatchSpan.Finish() + close(dispatchDone) + }() for _, candidate := range transactionProfileCandidates { jobs <- profile.CallTreesReadJob{ @@ -412,10 +415,15 @@ func GetFlamegraphFromCandidates( flamegraphSpan := sentry.StartSpan(ctx, "processing candidates") numCandidates := len(transactionProfileCandidates) + len(continuousProfileCandidates) + var processingErr error for i := 0; i < numCandidates; i++ { res := <-results + if processingErr != nil { + continue + } + err := res.Error() if err != nil { if errors.Is(err, storageutil.ErrObjectNotFound) { @@ -495,14 +503,17 @@ func GetFlamegraphFromCandidates( } chunkProfileSpan.Finish() } else { - // This should never happen - flamegraphSpan.Finish() - return speedscope.Output{}, errors.New("unexpected result from storage") + processingErr = errors.New("unexpected result from storage") } } + <-dispatchDone flamegraphSpan.Finish() + if processingErr != nil { + return speedscope.Output{}, processingErr + } + serializeSpan := sentry.StartSpan(ctx, "serialize") defer serializeSpan.Finish()