mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: use unique workspace owners over unique users (#11044)
This commit is contained in:
@@ -52,6 +52,7 @@ type Cache struct {
|
||||
deploymentDAUResponses atomic.Pointer[map[int]codersdk.DAUsResponse]
|
||||
templateDAUResponses atomic.Pointer[map[int]map[uuid.UUID]codersdk.DAUsResponse]
|
||||
templateUniqueUsers atomic.Pointer[map[uuid.UUID]int]
|
||||
templateWorkspaceOwners atomic.Pointer[map[uuid.UUID]int]
|
||||
templateAverageBuildTime atomic.Pointer[map[uuid.UUID]database.GetTemplateAverageBuildTimeRow]
|
||||
deploymentStatsResponse atomic.Pointer[codersdk.DeploymentStats]
|
||||
|
||||
@@ -206,6 +207,7 @@ func (c *Cache) refreshTemplateDAUs(ctx context.Context) error {
|
||||
var (
|
||||
templateDAUs = make(map[int]map[uuid.UUID]codersdk.DAUsResponse, len(templates))
|
||||
templateUniqueUsers = make(map[uuid.UUID]int)
|
||||
templateWorkspaceOwners = make(map[uuid.UUID]int)
|
||||
templateAverageBuildTimes = make(map[uuid.UUID]database.GetTemplateAverageBuildTimeRow)
|
||||
)
|
||||
|
||||
@@ -214,7 +216,9 @@ func (c *Cache) refreshTemplateDAUs(ctx context.Context) error {
|
||||
return xerrors.Errorf("deployment daus: %w", err)
|
||||
}
|
||||
|
||||
ids := make([]uuid.UUID, 0, len(templates))
|
||||
for _, template := range templates {
|
||||
ids = append(ids, template.ID)
|
||||
for _, tzOffset := range templateTimezoneOffsets {
|
||||
rows, err := c.database.GetTemplateDAUs(ctx, database.GetTemplateDAUsParams{
|
||||
TemplateID: template.ID,
|
||||
@@ -249,6 +253,17 @@ func (c *Cache) refreshTemplateDAUs(ctx context.Context) error {
|
||||
}
|
||||
templateAverageBuildTimes[template.ID] = templateAvgBuildTime
|
||||
}
|
||||
|
||||
owners, err := c.database.GetWorkspaceUniqueOwnerCountByTemplateIDs(ctx, ids)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get workspace unique owner count by template ids: %w", err)
|
||||
}
|
||||
|
||||
for _, owner := range owners {
|
||||
templateWorkspaceOwners[owner.TemplateID] = int(owner.UniqueOwnersSum)
|
||||
}
|
||||
|
||||
c.templateWorkspaceOwners.Store(&templateWorkspaceOwners)
|
||||
c.templateDAUResponses.Store(&templateDAUs)
|
||||
c.templateUniqueUsers.Store(&templateUniqueUsers)
|
||||
c.templateAverageBuildTime.Store(&templateAverageBuildTimes)
|
||||
@@ -469,6 +484,21 @@ func (c *Cache) TemplateBuildTimeStats(id uuid.UUID) codersdk.TemplateBuildTimeS
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cache) TemplateWorkspaceOwners(id uuid.UUID) (int, bool) {
|
||||
m := c.templateWorkspaceOwners.Load()
|
||||
if m == nil {
|
||||
// Data loading.
|
||||
return -1, false
|
||||
}
|
||||
|
||||
resp, ok := (*m)[id]
|
||||
if !ok {
|
||||
// Probably no data.
|
||||
return -1, false
|
||||
}
|
||||
return resp, true
|
||||
}
|
||||
|
||||
func (c *Cache) DeploymentStats() (codersdk.DeploymentStats, bool) {
|
||||
deploymentStats := c.deploymentStatsResponse.Load()
|
||||
if deploymentStats == nil {
|
||||
|
||||
@@ -254,6 +254,74 @@ func TestCache_TemplateUsers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCache_TemplateWorkspaceOwners(t *testing.T) {
|
||||
t.Parallel()
|
||||
var ()
|
||||
|
||||
var (
|
||||
db = dbmem.New()
|
||||
cache = metricscache.New(db, slogtest.Make(t, nil), metricscache.Intervals{
|
||||
TemplateDAUs: testutil.IntervalFast,
|
||||
})
|
||||
)
|
||||
|
||||
defer cache.Close()
|
||||
|
||||
user1 := dbgen.User(t, db, database.User{})
|
||||
user2 := dbgen.User(t, db, database.User{})
|
||||
template := dbgen.Template(t, db, database.Template{
|
||||
Provisioner: database.ProvisionerTypeEcho,
|
||||
})
|
||||
require.Eventuallyf(t, func() bool {
|
||||
count, ok := cache.TemplateWorkspaceOwners(template.ID)
|
||||
return ok && count == 0
|
||||
}, testutil.WaitShort, testutil.IntervalMedium,
|
||||
"TemplateWorkspaceOwners never populated 0 owners",
|
||||
)
|
||||
|
||||
dbgen.Workspace(t, db, database.Workspace{
|
||||
TemplateID: template.ID,
|
||||
OwnerID: user1.ID,
|
||||
})
|
||||
|
||||
require.Eventuallyf(t, func() bool {
|
||||
count, _ := cache.TemplateWorkspaceOwners(template.ID)
|
||||
return count == 1
|
||||
}, testutil.WaitShort, testutil.IntervalMedium,
|
||||
"TemplateWorkspaceOwners never populated 1 owner",
|
||||
)
|
||||
|
||||
workspace2 := dbgen.Workspace(t, db, database.Workspace{
|
||||
TemplateID: template.ID,
|
||||
OwnerID: user2.ID,
|
||||
})
|
||||
|
||||
require.Eventuallyf(t, func() bool {
|
||||
count, _ := cache.TemplateWorkspaceOwners(template.ID)
|
||||
return count == 2
|
||||
}, testutil.WaitShort, testutil.IntervalMedium,
|
||||
"TemplateWorkspaceOwners never populated 2 owners",
|
||||
)
|
||||
|
||||
// 3rd workspace should not be counted since we have the same owner as workspace2.
|
||||
dbgen.Workspace(t, db, database.Workspace{
|
||||
TemplateID: template.ID,
|
||||
OwnerID: user1.ID,
|
||||
})
|
||||
|
||||
db.UpdateWorkspaceDeletedByID(context.Background(), database.UpdateWorkspaceDeletedByIDParams{
|
||||
ID: workspace2.ID,
|
||||
Deleted: true,
|
||||
})
|
||||
|
||||
require.Eventuallyf(t, func() bool {
|
||||
count, _ := cache.TemplateWorkspaceOwners(template.ID)
|
||||
return count == 1
|
||||
}, testutil.WaitShort, testutil.IntervalMedium,
|
||||
"TemplateWorkspaceOwners never populated 1 owner after delete",
|
||||
)
|
||||
}
|
||||
|
||||
func clockTime(t time.Time, hour, minute, sec int) time.Time {
|
||||
return time.Date(t.Year(), t.Month(), t.Day(), hour, minute, sec, t.Nanosecond(), t.Location())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user