From d0875a51b2f07766b339b34a580d4e6e9fab348d Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Sun, 23 Aug 2026 11:44:41 +0200 Subject: Handle Strava rate limiting with abort, retry time and daily usage display Strava sync for 167 rides exceeds the 100/15-min read limit (2 calls per ride). Previously a 429 was treated as a skipped ride, so every remaining ride also failed silently. Now GetJSON returns a typed RateLimitError with RetryAfter computed from Retry-After/Date and X-RateLimit headers (15-min window resets at :00/:15/:30/:45, daily at midnight UTC) and tracks Read/Overall usage. syncRides aborts on 429 with partial progress instead of skipping, and handleSync emits an SSE error with retry time, daily usage vs limit and structured rateLimit snapshot; progress and complete events also carry the snapshot for the UI to display. Frontend shows Read daily/15-min usage in progress details and on completion. --- web/views.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'web/views.go') diff --git a/web/views.go b/web/views.go index 6fd5adf..cfb31e5 100644 --- a/web/views.go +++ b/web/views.go @@ -9,6 +9,7 @@ import ( "github.com/martinlehoux/biking_home/official_climb" "github.com/martinlehoux/biking_home/ride" "github.com/martinlehoux/biking_home/rideanalysis" + "github.com/martinlehoux/biking_home/strava" ) type RideView struct { @@ -376,11 +377,17 @@ type SyncPageData struct { HasAuth bool } +type RateLimitSnapshot struct { + Read strava.RateLimit `json:"read"` + Overall strava.RateLimit `json:"overall"` +} + type SyncProgress struct { - Total int `json:"total"` - Completed int `json:"completed"` - Imported int `json:"imported"` - Skipped int `json:"skipped"` + Total int `json:"total"` + Completed int `json:"completed"` + Imported int `json:"imported"` + Skipped int `json:"skipped"` + RateLimit *RateLimitSnapshot `json:"rateLimit,omitempty"` } func formatRideDate(value time.Time) string { -- cgit v1.3