Skip to content

Commit b502940

Browse files
committed
Pass time offsets to metricscache
1 parent 45e8342 commit b502940

File tree

3 files changed

+66
-15
lines changed

3 files changed

+66
-15
lines changed

coderd/insights.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func (api *API) deploymentDAUs(rw http.ResponseWriter, r *http.Request) {
2222
return
2323
}
2424

25-
resp, _ := api.metricsCache.DeploymentDAUs()
25+
_, resp, _ := api.metricsCache.DeploymentDAUs(0)
2626
if resp == nil || resp.Entries == nil {
2727
httpapi.Write(ctx, rw, http.StatusOK, &codersdk.DAUsResponse{
2828
Entries: []codersdk.DAUEntry{},

coderd/metricscache/metricscache.go

Lines changed: 64 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"database/sql"
66
"fmt"
7+
"math"
78
"sync"
89
"sync/atomic"
910
"time"
@@ -30,8 +31,8 @@ type Cache struct {
3031
log slog.Logger
3132
intervals Intervals
3233

33-
deploymentDAUResponses atomic.Pointer[codersdk.DAUsResponse]
34-
templateDAUResponses atomic.Pointer[map[uuid.UUID]codersdk.DAUsResponse]
34+
deploymentDAUResponses atomic.Pointer[map[int]codersdk.DAUsResponse]
35+
templateDAUResponses atomic.Pointer[map[int]map[uuid.UUID]codersdk.DAUsResponse]
3536
templateUniqueUsers atomic.Pointer[map[uuid.UUID]int]
3637
templateAverageBuildTime atomic.Pointer[map[uuid.UUID]database.GetTemplateAverageBuildTimeRow]
3738
deploymentStatsResponse atomic.Pointer[codersdk.DeploymentStats]
@@ -161,8 +162,8 @@ func (c *Cache) refreshTemplateDAUs(ctx context.Context) error {
161162
}
162163

163164
var (
164-
deploymentDAUs = codersdk.DAUsResponse{}
165-
templateDAUs = make(map[uuid.UUID]codersdk.DAUsResponse, len(templates))
165+
deploymentDAUs = map[int]codersdk.DAUsResponse{}
166+
templateDAUs = make(map[int]map[uuid.UUID]codersdk.DAUsResponse, len(templates))
166167
templateUniqueUsers = make(map[uuid.UUID]int)
167168
templateAverageBuildTimes = make(map[uuid.UUID]database.GetTemplateAverageBuildTimeRow)
168169
)
@@ -171,7 +172,7 @@ func (c *Cache) refreshTemplateDAUs(ctx context.Context) error {
171172
if err != nil {
172173
return err
173174
}
174-
deploymentDAUs = convertDAUResponse(rows)
175+
deploymentDAUs[0] = convertDAUResponse(rows)
175176
c.deploymentDAUResponses.Store(&deploymentDAUs)
176177

177178
for _, template := range templates {
@@ -182,7 +183,7 @@ func (c *Cache) refreshTemplateDAUs(ctx context.Context) error {
182183
if err != nil {
183184
return err
184185
}
185-
templateDAUs[template.ID] = convertDAUResponse(rows)
186+
templateDAUs[0][template.ID] = convertDAUResponse(rows)
186187
templateUniqueUsers[template.ID] = countUniqueUsers(rows)
187188

188189
templateAvgBuildTime, err := c.database.GetTemplateAverageBuildTime(ctx, database.GetTemplateAverageBuildTimeParams{
@@ -284,26 +285,76 @@ func (c *Cache) Close() error {
284285
return nil
285286
}
286287

287-
func (c *Cache) DeploymentDAUs() (*codersdk.DAUsResponse, bool) {
288+
func (c *Cache) DeploymentDAUs(offset int) (int, *codersdk.DAUsResponse, bool) {
288289
m := c.deploymentDAUResponses.Load()
289-
return m, m != nil
290+
if m == nil {
291+
return 0, nil, false
292+
}
293+
closestOffset, resp, ok := closest(*m, offset)
294+
if !ok {
295+
return 0, nil, false
296+
}
297+
return closestOffset, &resp, ok
290298
}
291299

292300
// TemplateDAUs returns an empty response if the template doesn't have users
293301
// or is loading for the first time.
294-
func (c *Cache) TemplateDAUs(id uuid.UUID) (*codersdk.DAUsResponse, bool) {
302+
// The cache will select the closest DAUs response to given timezone offset.
303+
func (c *Cache) TemplateDAUs(id uuid.UUID, offset int) (int, *codersdk.DAUsResponse, bool) {
295304
m := c.templateDAUResponses.Load()
296305
if m == nil {
297306
// Data loading.
298-
return nil, false
307+
return 0, nil, false
299308
}
300309

301-
resp, ok := (*m)[id]
310+
closestOffset, resp, ok := closest(*m, offset)
302311
if !ok {
303312
// Probably no data.
304-
return nil, false
313+
return 0, nil, false
314+
}
315+
316+
tpl, ok := resp[id]
317+
if !ok {
318+
// Probably no data.
319+
return 0, nil, false
320+
}
321+
322+
return closestOffset, &tpl, true
323+
}
324+
325+
// closest returns the value in the values map that has a key with the value most
326+
// close to the requested key. This is so if a user requests a timezone offset that
327+
// we do not have, we return the closest one we do have to the user.
328+
func closest[V any](values map[int]V, offset int) (int, V, bool) {
329+
if len(values) == 0 {
330+
var v V
331+
return -1, v, false
332+
}
333+
334+
v, ok := values[offset]
335+
if ok {
336+
// We have the exact offset, that was easy!
337+
return offset, v, true
338+
}
339+
340+
var closest int
341+
var closestV V
342+
diff := math.MaxInt
343+
for k, v := range values {
344+
if abs(k-offset) < diff {
345+
// new closest
346+
closest = k
347+
closestV = v
348+
}
349+
}
350+
return closest, closestV, true
351+
}
352+
353+
func abs(a int) int {
354+
if a < 0 {
355+
return -1 * a
305356
}
306-
return &resp, true
357+
return a
307358
}
308359

309360
// TemplateUniqueUsers returns the number of unique Template users

coderd/templates.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ func (api *API) templateDAUs(rw http.ResponseWriter, r *http.Request) {
620620
ctx := r.Context()
621621
template := httpmw.TemplateParam(r)
622622

623-
resp, _ := api.metricsCache.TemplateDAUs(template.ID)
623+
_, resp, _ := api.metricsCache.TemplateDAUs(template.ID, 0)
624624
if resp == nil || resp.Entries == nil {
625625
httpapi.Write(ctx, rw, http.StatusOK, &codersdk.DAUsResponse{
626626
Entries: []codersdk.DAUEntry{},

0 commit comments

Comments
 (0)