Skip to content

Commit

Permalink
refactor: improve the partitioning window calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
adityathebe committed Jul 6, 2023
1 parent c2ccedc commit 72020fd
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 34 deletions.
44 changes: 25 additions & 19 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,11 @@ func CheckDetails(c echo.Context) error {
return c.JSON(http.StatusOK, DetailResponse{})
}

checkSummary := *summary[0]
checkSummary := summary[0]
totalChecks := checkSummary.TotalRuns
if totalChecks <= desiredNumOfCheckStatuses {
q.WindowDuration = 0 // No need to perform window aggregation
} else {
rangeDuration := checkSummary.LatestRuntime.Sub(*checkSummary.EarliestRuntime)
q.WindowDuration = getBestPartitioner(rangeDuration)
}

rangeDuration := checkSummary.LatestRuntime.Sub(*checkSummary.EarliestRuntime)
q.WindowDuration = getBestPartitioner(totalChecks, rangeDuration)

results, err := cache.PostgresCache.QueryStatus(c.Request().Context(), *q)
if err != nil {
Expand Down Expand Up @@ -133,27 +130,36 @@ func HealthSummary(c echo.Context) error {
return c.JSON(http.StatusOK, apiResponse)
}

// getBestPartitioner returns best window duration to partition the
// given duration such that the partition is close to the desired value.
func getBestPartitioner(rangeDuration time.Duration) time.Duration {
func getBestPartitioner(totalChecks int, rangeDuration time.Duration) time.Duration {
if totalChecks <= desiredNumOfCheckStatuses {
return 0 // No need to perform window aggregation
}

bestDelta := 100000000 // sufficiently large delta to begin with
bestWindow := allowedWindows[0]

for i, wp := range allowedWindows {
for _, wp := range allowedWindows {
numWindows := int(rangeDuration / wp)
delta := abs(desiredNumOfCheckStatuses - numWindows)

if delta < bestDelta {
bestDelta = delta
continue
}

// as soon as we notice that the delta gets worse, we return the previous window
if i == 0 {
return wp
bestWindow = wp
} else {
// as soon as we notice that the delta gets worse, we break the loop
break
}
}

return allowedWindows[i-1]
numWindows := int(rangeDuration / bestWindow)
if abs(desiredNumOfCheckStatuses-totalChecks) <= abs(desiredNumOfCheckStatuses-numWindows) {
// If this best partition creates windows such that the resulting number of data points deviate more
// from the desired data points than the actual data points, then we do not aggregate.
// Example: if there are 144 checks for the duration of 6 days,
// then the best partition, 1 hour, would generate 144 data points.
// But the original data points (120) are closer to 100, so we do not aggregate.
return 0
}

return allowedWindows[len(allowedWindows)-1]
return bestWindow
}
36 changes: 21 additions & 15 deletions pkg/api/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,31 @@ func Test_getMostSuitableWindowDuration(t *testing.T) {
day := time.Hour * 24

tests := []struct {
schedule time.Duration // how often the check is run
rangeDuration time.Duration
expected time.Duration
expected time.Duration // the best duration to partition the range
}{
{time.Minute * 5, time.Minute},
{time.Minute * 30, time.Minute},
{time.Hour * 2, time.Minute},
{time.Hour * 12, time.Minute * 5},
{day * 2, time.Minute * 30},
{day * 8, time.Hour * 3},
{day * 30, time.Hour * 6},
{day * 90, day},
{day * 365, day * 7},
{time.Second * 30, time.Minute * 5, 0},
{time.Second * 30, time.Minute * 30, 0},
{time.Second * 30, time.Hour * 2, time.Minute},
{time.Second * 30, time.Hour * 12, time.Minute * 5},
{time.Second * 30, day * 2, time.Minute * 30},
{time.Hour, day * 4, 0},
{time.Hour, day * 5, 0},
{time.Hour, day * 6, 0},
{time.Hour, day * 12, time.Hour * 3},
{time.Second * 30, day * 8, time.Hour * 3},
{time.Second * 30, day * 30, time.Hour * 6},
{time.Second * 30, day * 90, day},
{time.Second * 30, day * 365, day * 7},
}

for _, test := range tests {
t.Run(test.rangeDuration.String(), func(t *testing.T) {
result := getBestPartitioner(test.rangeDuration)
if result != test.expected {
t.Errorf("expected %v, but got %v", test.expected, result)
for _, td := range tests {
t.Run(td.rangeDuration.String(), func(t *testing.T) {
totalChecks := int(td.rangeDuration / td.schedule)
result := getBestPartitioner(totalChecks, td.rangeDuration)
if result != td.expected {
t.Errorf("expected %v, but got %v", td.expected, result)
}
})
}
Expand Down

0 comments on commit 72020fd

Please sign in to comment.