Skip to content

Commit d6ce0b7

Browse files
authored
fix: lastTransitionedTime never populated due to self-comparison (#3001)
1 parent fb5bce0 commit d6ce0b7

4 files changed

Lines changed: 26 additions & 14 deletions

File tree

pkg/api/run_now.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"errors"
55
"fmt"
66
"net/http"
7+
"time"
78

89
"github.com/flanksource/canary-checker/api/context"
910
v1 "github.com/flanksource/canary-checker/api/v1"
@@ -58,6 +59,10 @@ func RunCanaryHandler(c echo.Context) error {
5859
return nil
5960
}
6061

62+
// Capture the cutoff before persisting so LatestCheckStatus excludes the
63+
// current run's just-saved status and compares against the prior state.
64+
now := time.Now()
65+
6166
for _, result := range results {
6267
if _, err := cache.PostgresCache.Add(ctx.Context, pkg.FromV1(result.Canary, result.Check), pkg.CheckStatusFromResult(*result)); err != nil {
6368
return errorResponse(c, err, http.StatusInternalServerError)
@@ -68,7 +73,7 @@ func RunCanaryHandler(c echo.Context) error {
6873
}
6974
}
7075

71-
canaryJobs.UpdateCanaryStatusAndEvent(ctx.Context, *canary, results)
76+
canaryJobs.UpdateCanaryStatusAndEvent(ctx.Context, *canary, results, now)
7277
return c.JSON(http.StatusOK, results[0])
7378
}
7479

pkg/db/canary.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,20 @@ func GetTransformedCheckIDs(ctx context.Context, canaryID string, excludeTypes .
174174
return ids, err
175175
}
176176

177-
func LatestCheckStatus(ctx context.Context, checkID string) (*models.CheckStatus, error) {
177+
// LatestCheckStatus returns the most recent check_statuses row for the given
178+
// check that was recorded strictly before the given cutoff. The cutoff must
179+
// predate the current run's persisted status so that the current result is
180+
// excluded and the returned row reflects the prior state. This is required
181+
// because SaveResults commits the current run's status before this lookup.
182+
func LatestCheckStatus(ctx context.Context, checkID string, before time.Time) (*models.CheckStatus, error) {
178183
if checkID == "" || uuid.Nil.String() == checkID {
179184
return nil, nil
180185
}
181186
var status models.CheckStatus
182-
if err := ctx.DB().Limit(1).Select("time, created_at, status").Where("check_id = ?", checkID).Order("time DESC").Find(&status).Error; err != nil {
187+
err := ctx.DB().Select("time, created_at, status").
188+
Where("check_id = ? AND time < ?", checkID, before.UTC().Format(time.RFC3339)).
189+
Order("time DESC").Take(&status).Error
190+
if err != nil {
183191
if errors.Is(err, gorm.ErrRecordNotFound) {
184192
return nil, nil
185193
}

pkg/jobs/canary/canary_jobs.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,16 @@ func (j CanaryJob) Run(ctx dutyjob.JobRuntime) error {
128128
}
129129
}
130130

131+
// Capture the cutoff before SaveResults so LatestCheckStatus excludes the
132+
// current run's just-persisted status and compares against the prior state.
133+
now := time.Now()
134+
131135
transformedChecksCreated, checkIDDeleteStrategyMap, err := SaveResults(ctx.Context, results)
132136
if err != nil {
133137
return fmt.Errorf("failed to save results: %w", err)
134138
}
135139

136-
UpdateCanaryStatusAndEvent(ctx.Context, j.Canary, results)
140+
UpdateCanaryStatusAndEvent(ctx.Context, j.Canary, results, now)
137141

138142
checkDeleteStrategyGroup := make(map[string][]string)
139143
checkIDsToRemove := utils.SetDifference(existingTransformedChecks, transformedChecksCreated)

pkg/jobs/canary/status.go

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import (
1717
"k8s.io/apimachinery/pkg/types"
1818
)
1919

20-
func UpdateCanaryStatusAndEvent(ctx context.Context, canary v1.Canary, results []*pkg.CheckResult) {
20+
func UpdateCanaryStatusAndEvent(ctx context.Context, canary v1.Canary, results []*pkg.CheckResult, now time.Time) {
2121
if CanaryStatusChannel == nil {
2222
return
2323
}
@@ -40,7 +40,6 @@ func UpdateCanaryStatusAndEvent(ctx context.Context, canary v1.Canary, results [
4040
var highestLatency float64
4141
var uptimeAgg dutyTypes.Uptime
4242

43-
transitioned := false
4443
for _, result := range results {
4544
// Increment duration
4645
duration += result.Duration
@@ -62,26 +61,22 @@ func UpdateCanaryStatusAndEvent(ctx context.Context, canary v1.Canary, results [
6261
highestLatency = latency.Rolling1H
6362
}
6463

64+
transitioned := false
6565
// Transition
6666
// q := query.CheckQueryParams{Check: checkID, StatusCount: 1}
6767
// if canary.Status.LastTransitionedTime != nil {
6868
// q.Start = canary.Status.LastTransitionedTime.Format(time.RFC3339)
6969
// }
7070

71-
latestCheckStatus, err := db.LatestCheckStatus(ctx, checkID)
71+
latestCheckStatus, err := db.LatestCheckStatus(ctx, checkID, now)
7272
if err != nil || latestCheckStatus == nil {
7373
transitioned = true
7474
} else if latestCheckStatus.Status != result.Pass {
7575
transitioned = true
7676
}
7777
if transitioned {
78-
transitionTime := time.Now()
79-
if latestCheckStatus != nil {
80-
transitionTime = latestCheckStatus.CreatedAt
81-
}
82-
83-
checkStatus[checkID].LastTransitionedTime = &metav1.Time{Time: transitionTime}
84-
lastTransitionedTime = &metav1.Time{Time: transitionTime}
78+
checkStatus[checkID].LastTransitionedTime = &metav1.Time{Time: now}
79+
lastTransitionedTime = &metav1.Time{Time: now}
8580
}
8681

8782
if result.Message != "" {

0 commit comments

Comments
 (0)