Skip to content

Commit 6526371

Browse files
committed
feat: enhance error handling for external score updates in ScoreService
1 parent abd8d0b commit 6526371

1 file changed

Lines changed: 43 additions & 5 deletions

File tree

internal/service/score_service.go

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package service
22

33
import (
4+
"errors"
45
"fmt"
6+
"io"
57
"net/http"
8+
"strings"
69

710
"github.com/UDL-TF/UnitedAPI/internal/logger"
811
"github.com/UDL-TF/UnitedAPI/internal/model"
@@ -41,8 +44,9 @@ func (s *ScoreService) ProcessScoreData(scoreData *model.ScoreData) error {
4144

4245
// Call external API to update scores
4346
if err := s.updateScores(scoreData.MatchID); err != nil {
44-
logger.Log.Error("Failed to update scores via external API", zap.Error(err))
45-
return fmt.Errorf("error updating scores: %w", err)
47+
if handledErr := s.handleScoreUpdateError(scoreData.MatchID, "Failed to update scores via external API", err); handledErr != nil {
48+
return handledErr
49+
}
4650
}
4751

4852
// Check if all rounds are done
@@ -83,8 +87,9 @@ func (s *ScoreService) completeMatch(matchID int) error {
8387
}
8488

8589
if err := s.updateScores(matchID); err != nil {
86-
logger.Log.Error("Failed to update scores via external API after completion", zap.Error(err), zap.Int("matchID", matchID))
87-
return fmt.Errorf("error updating scores: %w", err)
90+
if handledErr := s.handleScoreUpdateError(matchID, "Failed to update scores via external API after completion", err); handledErr != nil {
91+
return handledErr
92+
}
8893
}
8994

9095
return nil
@@ -107,9 +112,42 @@ func (s *ScoreService) updateScores(matchID int) error {
107112
}
108113
defer resp.Body.Close()
109114

115+
bodyBytes, _ := io.ReadAll(resp.Body)
110116
if resp.StatusCode != http.StatusOK {
111-
return fmt.Errorf("external API returned non-200 status: %d", resp.StatusCode)
117+
return &ScoreUpdateError{StatusCode: resp.StatusCode, Body: strings.TrimSpace(string(bodyBytes))}
112118
}
113119

114120
return nil
115121
}
122+
123+
// handleScoreUpdateError centralizes how we react to external score sync failures
124+
func (s *ScoreService) handleScoreUpdateError(matchID int, logMessage string, err error) error {
125+
var scoreErr *ScoreUpdateError
126+
if errors.As(err, &scoreErr) && scoreErr.StatusCode == http.StatusUnprocessableEntity {
127+
logger.Log.Warn(logMessage,
128+
zap.Int("matchID", matchID),
129+
zap.Int("status", scoreErr.StatusCode),
130+
zap.String("externalMessage", scoreErr.Body))
131+
return nil
132+
}
133+
134+
logger.Log.Error(logMessage, zap.Error(err), zap.Int("matchID", matchID))
135+
return fmt.Errorf("error updating scores: %w", err)
136+
}
137+
138+
// ScoreUpdateError captures structured details from the external API when it fails
139+
type ScoreUpdateError struct {
140+
StatusCode int
141+
Body string
142+
}
143+
144+
// Error implements the error interface for ScoreUpdateError
145+
func (e *ScoreUpdateError) Error() string {
146+
if e == nil {
147+
return ""
148+
}
149+
if e.Body != "" {
150+
return fmt.Sprintf("external API returned status %d: %s", e.StatusCode, e.Body)
151+
}
152+
return fmt.Sprintf("external API returned status %d", e.StatusCode)
153+
}

0 commit comments

Comments
 (0)