From 1cc26805bbd2752bab4362d02f5af4c5febf78a5 Mon Sep 17 00:00:00 2001 From: tejasva-vardhan Date: Mon, 6 Apr 2026 18:48:43 +0530 Subject: [PATCH] fix(gtfs): honor context cancellation and fix swallowed errors in AdvancedDirectionCalculator --- internal/gtfs/advanced_direction_calculator.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/internal/gtfs/advanced_direction_calculator.go b/internal/gtfs/advanced_direction_calculator.go index ea31987e..29c928a1 100644 --- a/internal/gtfs/advanced_direction_calculator.go +++ b/internal/gtfs/advanced_direction_calculator.go @@ -109,26 +109,27 @@ func (adc *AdvancedDirectionCalculator) CalculateStopDirection(ctx context.Conte // Fall back to computing from shapes, protected by singleflight // This ensures concurrent requests for the SAME stopID don't hit the DB multiple times. - v, _, _ := adc.requestGroup.Do(stopID, func() (interface{}, error) { + v, err, _ := adc.requestGroup.Do(stopID, func() (interface{}, error) { // Double-check cache inside the singleflight in case another goroutine just finished it if cached, ok := adc.directionResults.Load(stopID); ok { return cached.(string), nil } // Actually compute it (Hits the DB) - computedDir, err := adc.computeFromShapes(context.WithoutCancel(ctx), stopID) + computedDir, err := adc.computeFromShapes(ctx, stopID) + if err != nil { + return "", err + } // Only cache when there was no transient error. A transient error (e.g. DB // connection lost) must not permanently poison the cache; omitting it here // means the next request will retry the DB. - if err == nil { - adc.directionResults.Store(stopID, computedDir) - } - - // Intentionally return nil so singleflight shares the empty fallback result with concurrent callers. - // Since we skip caching on error, future requests will safely retry the DB. + adc.directionResults.Store(stopID, computedDir) return computedDir, nil }) + if err != nil { + return "" + } return v.(string) }