Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
142 commits
Select commit Hold shift + click to select a range
ed531d9
chore(coderd/notifications): sync formatting and rendered-template go…
jaaydenh Aug 10, 2026
233795f
fix: enforce uniqueness and hour alignment for agent runtime usage ev…
jaaydenh Aug 10, 2026
3359ec5
feat: report stable license measurement diagnostics and tolerate unus…
jaaydenh Aug 10, 2026
69e8b95
feat: report agent runtime hours usage in entitlements
jaaydenh Aug 10, 2026
b485c5a
revert: "chore(coderd/notifications): sync formatting and rendered-te…
jaaydenh Aug 10, 2026
b7cae3d
Merge branch 'runtime-invariants' into license-measure-diagnostics
jaaydenh Aug 10, 2026
1d0dac8
Merge branch 'license-measure-diagnostics' into runtime-hours-entitle…
jaaydenh Aug 10, 2026
978b8d3
Merge remote-tracking branch 'origin/main' into runtime-invariants
jaaydenh Aug 10, 2026
258a368
Merge branch 'runtime-invariants' into license-measure-diagnostics
jaaydenh Aug 10, 2026
fa2f98b
Merge branch 'license-measure-diagnostics' into runtime-hours-entitle…
jaaydenh Aug 10, 2026
109ff26
updates for PR review
jaaydenh Aug 10, 2026
e679d63
updates for PR review
jaaydenh Aug 10, 2026
8f661c1
feat(enterprise/coderd/license): decode -1 runtime hours allocation a…
jaaydenh Aug 11, 2026
02b55b0
Merge branch 'license-measure-diagnostics' into runtime-hours-entitle…
jaaydenh Aug 11, 2026
c865ff2
feat: support unlimited agent runtime hours in entitlements
jaaydenh Aug 11, 2026
00d3249
chore: remove data-variant
jaaydenh Aug 11, 2026
3d8940c
chore(coderd/database): restore original InsertUsageEvent comment
jaaydenh Aug 11, 2026
0f8b1ab
Merge branch 'license-measure-diagnostics' into runtime-hours-entitle…
jaaydenh Aug 11, 2026
790c22d
Merge branch 'runtime-invariants' into runtime-hours-entitlements
jaaydenh Aug 11, 2026
8013af1
chore: remove and simplify explanatory comments
jaaydenh Aug 11, 2026
ef34856
Merge remote-tracking branch 'origin/main' into runtime-invariants
jaaydenh Aug 11, 2026
68b0295
fix(coderd/database): renumber agent runtime invariants migration to …
jaaydenh Aug 11, 2026
de3da4e
Merge branch 'runtime-invariants' into HEAD
jaaydenh Aug 11, 2026
1cbb069
Merge branch 'license-measure-diagnostics' into runtime-hours-entitle…
jaaydenh Aug 11, 2026
8d5606b
chore(enterprise/coderd/usage): restore agent runtime requeue guidanc…
jaaydenh Aug 11, 2026
27584cd
chore(site/src/modules/dashboard/LicenseBanner): remove comments narr…
jaaydenh Aug 11, 2026
f7447af
fix: make unlimited usage period features outrank metered ones on ties
jaaydenh Aug 11, 2026
2b97805
Merge remote-tracking branch 'origin/license-measure-diagnostics' int…
jaaydenh Aug 12, 2026
78e4477
fix(enterprise/coderd/license): accept issuer-valid zero soft limit f…
jaaydenh Aug 12, 2026
4661ddd
fix: address restack test failures and banner equality semantics
jaaydenh Aug 12, 2026
9d38c7a
Merge remote-tracking branch 'origin/main' into ri-fix
jaaydenh Aug 12, 2026
c8161e1
fix(coderd/database): renumber agent runtime invariants migration to …
jaaydenh Aug 12, 2026
f3374c4
Merge branch 'ri-fix' into license-measure-diagnostics
jaaydenh Aug 12, 2026
dbf6970
Merge remote-tracking branch 'origin/license-measure-diagnostics' int…
jaaydenh Aug 12, 2026
96fc0bc
chore(coderd/notifications): sync formatting and rendered-template go…
jaaydenh Aug 10, 2026
5c010c6
fix: enforce uniqueness and hour alignment for agent runtime usage ev…
jaaydenh Aug 10, 2026
cb36cfa
revert: "chore(coderd/notifications): sync formatting and rendered-te…
jaaydenh Aug 10, 2026
e127980
updates for PR review
jaaydenh Aug 10, 2026
d413cd9
chore(coderd/database): restore original InsertUsageEvent comment
jaaydenh Aug 11, 2026
273f068
fix(coderd/database): renumber agent runtime invariants migration to …
jaaydenh Aug 11, 2026
5e2f179
chore(enterprise/coderd/usage): restore agent runtime requeue guidanc…
jaaydenh Aug 11, 2026
c3ee285
fix(coderd/database): renumber agent runtime invariants migration to …
jaaydenh Aug 12, 2026
5779fcf
chore(enterprise/coderd/usage): correct ON CONFLICT concurrency comments
jaaydenh Aug 12, 2026
29bcb1c
feat: report stable license measurement diagnostics and tolerate unus…
jaaydenh Aug 10, 2026
5c5a928
feat(enterprise/coderd/license): decode -1 runtime hours allocation a…
jaaydenh Aug 11, 2026
1ec6150
chore: remove data-variant
jaaydenh Aug 11, 2026
2ed2fd5
chore: remove and simplify explanatory comments
jaaydenh Aug 11, 2026
3ea009a
fix: make unlimited usage period features outrank metered ones on ties
jaaydenh Aug 11, 2026
4b22ef0
fix(enterprise/coderd/license): accept issuer-valid zero soft limit f…
jaaydenh Aug 12, 2026
bfa6935
Merge remote-tracking branch 'origin/license-measure-diagnostics' int…
jaaydenh Aug 13, 2026
8fcb4b3
fix(coderd/notifications/dispatch): drop unused markdown import in sm…
jaaydenh Aug 13, 2026
a4bc61e
feat: report stable license measurement diagnostics and tolerate unus…
jaaydenh Aug 10, 2026
9d358f4
feat(enterprise/coderd/license): decode -1 runtime hours allocation a…
jaaydenh Aug 11, 2026
cd37639
chore: remove data-variant
jaaydenh Aug 11, 2026
99167d3
chore: remove and simplify explanatory comments
jaaydenh Aug 11, 2026
0fda91c
fix: make unlimited usage period features outrank metered ones on ties
jaaydenh Aug 11, 2026
97eab52
fix(enterprise/coderd/license): accept issuer-valid zero soft limit f…
jaaydenh Aug 12, 2026
829f829
Merge remote-tracking branch 'origin/license-measure-diagnostics' int…
jaaydenh Aug 13, 2026
a04611a
feat(enterprise/coderd/license): grandfather claim-less premium licen…
jaaydenh Aug 13, 2026
7e5b4b8
feat: report precise agent runtime milliseconds in entitlements
jaaydenh Aug 13, 2026
9c83be4
chore(coderd/notifications): sync formatting and rendered-template go…
jaaydenh Aug 10, 2026
5b38bab
fix: enforce uniqueness and hour alignment for agent runtime usage ev…
jaaydenh Aug 10, 2026
3255308
revert: "chore(coderd/notifications): sync formatting and rendered-te…
jaaydenh Aug 10, 2026
74bac4d
updates for PR review
jaaydenh Aug 10, 2026
b08cdff
chore(coderd/database): restore original InsertUsageEvent comment
jaaydenh Aug 11, 2026
414fa85
fix(coderd/database): renumber agent runtime invariants migration to …
jaaydenh Aug 11, 2026
6b0ea74
chore(enterprise/coderd/usage): restore agent runtime requeue guidanc…
jaaydenh Aug 11, 2026
8f174bb
fix(coderd/database): renumber agent runtime invariants migration to …
jaaydenh Aug 12, 2026
59ca444
chore(enterprise/coderd/usage): correct ON CONFLICT concurrency comments
jaaydenh Aug 12, 2026
e8efb48
fix(coderd/notifications/dispatch): drop unused markdown import in sm…
jaaydenh Aug 13, 2026
92cb793
feat: report stable license measurement diagnostics and tolerate unus…
jaaydenh Aug 10, 2026
967089d
feat(enterprise/coderd/license): decode -1 runtime hours allocation a…
jaaydenh Aug 11, 2026
0c87424
chore: remove data-variant
jaaydenh Aug 11, 2026
46ab198
chore: remove and simplify explanatory comments
jaaydenh Aug 11, 2026
1f6ef65
fix: make unlimited usage period features outrank metered ones on ties
jaaydenh Aug 11, 2026
2975cf4
fix(enterprise/coderd/license): accept issuer-valid zero soft limit f…
jaaydenh Aug 12, 2026
a143083
Merge remote-tracking branch 'origin/license-measure-diagnostics' int…
jaaydenh Aug 13, 2026
24577fb
chore: leave managed agent measurement untouched by license diagnostics
jaaydenh Aug 13, 2026
911ccb4
Merge remote-tracking branch 'origin/license-measure-diagnostics' int…
jaaydenh Aug 13, 2026
f80de75
chore(coderd): trim historical framing from invariant comments
jaaydenh Aug 14, 2026
727d233
refactor(enterprise/coderd/license): specialize usage measurement to …
jaaydenh Aug 14, 2026
86c2c85
fix(site/src/modules/dashboard/LicenseBanner): render notices heading…
jaaydenh Aug 14, 2026
e58a40d
chore(enterprise/coderd/license): document only current zero-allocati…
jaaydenh Aug 14, 2026
f69685f
Merge remote-tracking branch 'origin/main' into ri-fix
jaaydenh Aug 14, 2026
f60be11
fix(coderd/database): renumber agent runtime invariants migration to …
jaaydenh Aug 14, 2026
4ddb43a
Merge branch 'ri-fix' into license-measure-diagnostics
jaaydenh Aug 14, 2026
2083844
Merge remote-tracking branch 'origin/license-measure-diagnostics' int…
jaaydenh Aug 14, 2026
aa42e2c
chore(coderd/notifications): sync formatting and rendered-template go…
jaaydenh Aug 10, 2026
bfacbaf
fix: enforce uniqueness and hour alignment for agent runtime usage ev…
jaaydenh Aug 10, 2026
f82a41f
revert: "chore(coderd/notifications): sync formatting and rendered-te…
jaaydenh Aug 10, 2026
cd5540e
updates for PR review
jaaydenh Aug 10, 2026
49ba654
chore(coderd/database): restore original InsertUsageEvent comment
jaaydenh Aug 11, 2026
52d8e5d
fix(coderd/database): renumber agent runtime invariants migration to …
jaaydenh Aug 11, 2026
87c49d5
chore(enterprise/coderd/usage): restore agent runtime requeue guidanc…
jaaydenh Aug 11, 2026
41548ba
fix(coderd/database): renumber agent runtime invariants migration to …
jaaydenh Aug 12, 2026
9f38285
chore(enterprise/coderd/usage): correct ON CONFLICT concurrency comments
jaaydenh Aug 12, 2026
e9f3f26
fix(coderd/notifications/dispatch): drop unused markdown import in sm…
jaaydenh Aug 13, 2026
be402c1
chore(coderd): trim historical framing from invariant comments
jaaydenh Aug 14, 2026
95021df
fix(coderd/database): renumber agent runtime invariants migration to …
jaaydenh Aug 14, 2026
b468790
feat: report stable license measurement diagnostics and tolerate unus…
jaaydenh Aug 10, 2026
8ce55e2
feat(enterprise/coderd/license): decode -1 runtime hours allocation a…
jaaydenh Aug 11, 2026
9a9d240
chore: remove data-variant
jaaydenh Aug 11, 2026
3fb5f39
chore: remove and simplify explanatory comments
jaaydenh Aug 11, 2026
ba2f0ae
fix: make unlimited usage period features outrank metered ones on ties
jaaydenh Aug 11, 2026
489a607
fix(enterprise/coderd/license): accept issuer-valid zero soft limit f…
jaaydenh Aug 12, 2026
daf90f5
chore: leave managed agent measurement untouched by license diagnostics
jaaydenh Aug 13, 2026
ae15084
fix(site/src/modules/dashboard/LicenseBanner): render notices heading…
jaaydenh Aug 14, 2026
13b7fd1
chore(enterprise/coderd/license): document only current zero-allocati…
jaaydenh Aug 14, 2026
a22a335
Merge remote-tracking branch 'origin/license-measure-diagnostics' int…
jaaydenh Aug 17, 2026
1cec4c4
chore(coderd/notifications): sync formatting and rendered-template go…
jaaydenh Aug 10, 2026
06c925f
fix: enforce uniqueness and hour alignment for agent runtime usage ev…
jaaydenh Aug 10, 2026
5ef08aa
revert: "chore(coderd/notifications): sync formatting and rendered-te…
jaaydenh Aug 10, 2026
41e1a2d
updates for PR review
jaaydenh Aug 10, 2026
0c25db9
chore(coderd/database): restore original InsertUsageEvent comment
jaaydenh Aug 11, 2026
6982b2f
fix(coderd/database): renumber agent runtime invariants migration to …
jaaydenh Aug 11, 2026
99ab235
chore(enterprise/coderd/usage): restore agent runtime requeue guidanc…
jaaydenh Aug 11, 2026
92a01e2
fix(coderd/database): renumber agent runtime invariants migration to …
jaaydenh Aug 12, 2026
fd1be2f
chore(enterprise/coderd/usage): correct ON CONFLICT concurrency comments
jaaydenh Aug 12, 2026
33ff1b7
fix(coderd/notifications/dispatch): drop unused markdown import in sm…
jaaydenh Aug 13, 2026
92bfe85
chore(coderd): trim historical framing from invariant comments
jaaydenh Aug 14, 2026
f67ff01
fix(coderd/database): renumber agent runtime invariants migration to …
jaaydenh Aug 14, 2026
3790a2d
feat: report stable license measurement diagnostics and tolerate unus…
jaaydenh Aug 10, 2026
fb2c936
feat(enterprise/coderd/license): decode -1 runtime hours allocation a…
jaaydenh Aug 11, 2026
01bdfd0
chore: remove data-variant
jaaydenh Aug 11, 2026
40917af
chore: remove and simplify explanatory comments
jaaydenh Aug 11, 2026
18f5e7f
fix: make unlimited usage period features outrank metered ones on ties
jaaydenh Aug 11, 2026
c1300dd
fix(enterprise/coderd/license): accept issuer-valid zero soft limit f…
jaaydenh Aug 12, 2026
379db5c
chore: leave managed agent measurement untouched by license diagnostics
jaaydenh Aug 13, 2026
a379adc
fix(site/src/modules/dashboard/LicenseBanner): render notices heading…
jaaydenh Aug 14, 2026
fce4f79
chore(enterprise/coderd/license): document only current zero-allocati…
jaaydenh Aug 14, 2026
e243bfb
Merge remote-tracking branch 'origin/license-measure-diagnostics' int…
jaaydenh Aug 17, 2026
1338381
feat: report stable license measurement diagnostics and tolerate unus…
jaaydenh Aug 10, 2026
dff7735
feat(enterprise/coderd/license): decode -1 runtime hours allocation a…
jaaydenh Aug 11, 2026
4026657
chore: remove data-variant
jaaydenh Aug 11, 2026
04caac9
chore: remove and simplify explanatory comments
jaaydenh Aug 11, 2026
ce5b547
fix: make unlimited usage period features outrank metered ones on ties
jaaydenh Aug 11, 2026
5a29e12
fix(enterprise/coderd/license): accept issuer-valid zero soft limit f…
jaaydenh Aug 12, 2026
128d73d
chore: leave managed agent measurement untouched by license diagnostics
jaaydenh Aug 13, 2026
21575f1
fix(site/src/modules/dashboard/LicenseBanner): render notices heading…
jaaydenh Aug 14, 2026
845b6de
chore(enterprise/coderd/license): document only current zero-allocati…
jaaydenh Aug 14, 2026
a8d7acc
Merge remote-tracking branch 'origin/license-measure-diagnostics' int…
jaaydenh Aug 17, 2026
904eff8
Merge remote-tracking branch 'origin/main' into runtime-hours-entitle…
jaaydenh Aug 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions coderd/apidoc/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 8 additions & 2 deletions coderd/apidoc/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions coderd/database/dbauthz/dbauthz.go
Original file line number Diff line number Diff line change
Expand Up @@ -4949,6 +4949,13 @@ func (q *querier) GetTotalUsageDCManagedAgentsV1(ctx context.Context, arg databa
return q.db.GetTotalUsageDCManagedAgentsV1(ctx, arg)
}

func (q *querier) GetTotalUsageHBAgentRuntimeV1(ctx context.Context, arg database.GetTotalUsageHBAgentRuntimeV1Params) (int64, error) {
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceUsageEvent); err != nil {
return 0, err
}
return q.db.GetTotalUsageHBAgentRuntimeV1(ctx, arg)
}

func (q *querier) GetUnexpiredLicenses(ctx context.Context) ([]database.License, error) {
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceLicense); err != nil {
return nil, err
Expand Down
8 changes: 8 additions & 0 deletions coderd/database/dbauthz/dbauthz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6532,6 +6532,14 @@ func (s *MethodTestSuite) TestUsageEvents() {
}).Asserts(rbac.ResourceUsageEvent, policy.ActionRead)
}))

s.Run("GetTotalUsageHBAgentRuntimeV1", s.Mocked(func(db *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
db.EXPECT().GetTotalUsageHBAgentRuntimeV1(gomock.Any(), gomock.Any()).Return(int64(1), nil)
check.Args(database.GetTotalUsageHBAgentRuntimeV1Params{
StartTime: time.Time{},
EndTime: time.Time{},
}).Asserts(rbac.ResourceUsageEvent, policy.ActionRead)
}))

s.Run("ListUsageEventCreatedAtsByTypeSince", s.Mocked(func(db *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
params := database.ListUsageEventCreatedAtsByTypeSinceParams{
EventType: "hb_agent_runtime_v1",
Expand Down
8 changes: 8 additions & 0 deletions coderd/database/dbmetrics/querymetrics.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions coderd/database/dbmock/dbmock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions coderd/database/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 84 additions & 2 deletions coderd/database/querier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/coder/coder/v2/coderd/provisionerdserver"
"github.com/coder/coder/v2/coderd/rbac"
"github.com/coder/coder/v2/coderd/rbac/policy"
"github.com/coder/coder/v2/coderd/usage/usagetypes"
"github.com/coder/coder/v2/coderd/util/slice"
"github.com/coder/coder/v2/coderd/x/chatd/chatprompt"
"github.com/coder/coder/v2/codersdk"
Expand Down Expand Up @@ -10924,8 +10925,8 @@ func TestUsageEventsTrigger(t *testing.T) {
require.Len(t, rows, 3)

// The same bucket under a different id is not an idempotent
// re-insert but a duplicate that would double any aggregate summing
// runtime_ms; the unique partial index
// re-insert but a duplicate that would double the SUM in
// GetTotalUsageHBAgentRuntimeV1; the unique partial index
// idx_usage_events_agent_runtime rejects it loudly instead of the
// (id) arbiter silently dropping it.
err := db.InsertUsageEvent(ctx, database.InsertUsageEventParams{
Expand Down Expand Up @@ -10989,6 +10990,87 @@ func TestUsageEventsTrigger(t *testing.T) {
})
}

func TestGetTotalUsageHBAgentRuntimeV1(t *testing.T) {
t.Parallel()

ctx := testutil.Context(t, testutil.WaitLong)
db, _ := dbtestutil.NewDB(t)

// hb_agent_runtime_v1 events are one row per hourly bucket, created_at
// set to the bucket start.
hour := func(d, h int) time.Time {
return time.Date(2025, 1, d, h, 0, 0, 0, time.UTC)
}
// The event type and payload are built from the producer's types rather
// than hand-written literals, so a rename in usagetypes fails this test
// instead of leaving the query silently summing a key nothing writes.
insert := func(id string, runtimeMs int64, createdAt time.Time) {
t.Helper()
event := usagetypes.HBAgentRuntime{RuntimeMs: runtimeMs}
eventData, err := json.Marshal(event.Fields())
require.NoError(t, err)
err = db.InsertUsageEvent(ctx, database.InsertUsageEventParams{
ID: id,
EventType: string(event.EventType()),
EventData: eventData,
CreatedAt: createdAt,
})
require.NoError(t, err)
}
total := func(start, end time.Time) int64 {
t.Helper()
got, err := db.GetTotalUsageHBAgentRuntimeV1(ctx, database.GetTotalUsageHBAgentRuntimeV1Params{
StartTime: start,
EndTime: end,
})
require.NoError(t, err)
return got
}

// No events at all sums to zero rather than NULL.
require.EqualValues(t, 0, total(hour(1, 0), hour(5, 0)))

insert("rt-d1h0", 1000, hour(1, 0))
insert("rt-d1h12", 500, hour(1, 12))
insert("rt-d1h18", 0, hour(1, 18))
insert("rt-d2h0", 250, hour(2, 0))
insert("rt-d4h0", 7, hour(4, 0))

// A multi-day range sums every bucket it covers.
require.EqualValues(t, 1757, total(hour(1, 0), hour(5, 0)))

// The start bound is inclusive and the end bound is exclusive: a bucket
// starting exactly at the end timestamp belongs to the next period.
require.EqualValues(t, 1500, total(hour(1, 0), hour(2, 0)))
require.EqualValues(t, 1750, total(hour(1, 0), hour(2, 1)))
require.EqualValues(t, 250, total(hour(2, 0), hour(4, 0)))
require.EqualValues(t, 0, total(hour(3, 0), hour(4, 0)))

// Bounds are exact timestamps rather than whole days: a period starting
// mid-day excludes that day's earlier buckets.
require.EqualValues(t, 757, total(hour(1, 12), hour(5, 0)))

// A non-UTC timestamp addresses the same instant. Sydney is UTC+11 in
// January, so 23:00 on Jan 1 in Sydney is 12:00 on Jan 1 in UTC.
locSydney, err := time.LoadLocation("Australia/Sydney")
require.NoError(t, err)
require.EqualValues(t, 750, total(
time.Date(2025, 1, 1, 23, 0, 0, 0, locSydney),
time.Date(2025, 1, 2, 12, 0, 0, 0, locSydney),
))

// Other event types are never mixed in, even when they carry a
// runtime_ms key: without the event_type filter this would add 9999.
err = db.InsertUsageEvent(ctx, database.InsertUsageEventParams{
ID: "seats-1",
EventType: "hb_ai_seats_v1",
EventData: []byte(`{"count": 1, "runtime_ms": 9999}`),
CreatedAt: hour(1, 0),
})
require.NoError(t, err)
require.EqualValues(t, 1757, total(hour(1, 0), hour(5, 0)))
}

func TestGetTotalChatMessageRuntimeMsInRange(t *testing.T) {
t.Parallel()

Expand Down
38 changes: 38 additions & 0 deletions coderd/database/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions coderd/database/queries/usageevents.sql
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,28 @@ WHERE
-- Parentheses are necessary to avoid sqlc from generating an extra
-- argument.
AND day BETWEEN date_trunc('day', (@start_date::timestamptz) AT TIME ZONE 'UTC')::date AND date_trunc('day', (@end_date::timestamptz) AT TIME ZONE 'UTC')::date;

-- name: GetTotalUsageHBAgentRuntimeV1 :one
-- Gets the total Coder Agent runtime in milliseconds between two timestamps.
-- The start bound is inclusive and the end bound is exclusive.
--
-- Unlike GetTotalUsageDCManagedAgentsV1 this reads usage_events directly
-- rather than the usage_events_daily rollup: hb_agent_runtime_v1 is exactly
-- one row per hourly bucket deployment-wide, with created_at at the bucket
-- start, enforced by the unique partial index
-- idx_usage_events_agent_runtime (which also keeps SUM from counting a
-- bucket twice and serves this query). The result is bucket-granular: a
-- bucket counts entirely against the period containing its start. See
-- enterprise/coderd/usage/generator.go for what a bucket holds. If a
-- usage_events retention policy ever lands, this must move to the daily
-- rollup and accept day-granularity bounds.
SELECT
-- The first cast is necessary since you can't sum strings, and the second
-- cast is necessary to make sqlc happy.
COALESCE(SUM((event_data->>'runtime_ms')::bigint), 0)::bigint AS total_runtime_ms
FROM
usage_events
WHERE
event_type = 'hb_agent_runtime_v1'
AND created_at >= @start_time::timestamptz
AND created_at < @end_time::timestamptz;
28 changes: 28 additions & 0 deletions coderd/database/queries_internal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package database

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/coder/coder/v2/coderd/usage/usagetypes"
)

// TestGetTotalUsageHBAgentRuntimeV1QueryEventType pins the event type and
// payload extraction literals in the generated SQL to the Go producer.
// Renaming either would make this read-only query silently return 0 (->> on
// a missing key yields NULL, SUM skips NULLs, COALESCE reports 0), which is
// indistinguishable from zero usage at every layer above it.
func TestGetTotalUsageHBAgentRuntimeV1QueryEventType(t *testing.T) {
t.Parallel()

require.Contains(t, getTotalUsageHBAgentRuntimeV1,
string(usagetypes.UsageEventTypeHBAgentRuntimeV1))
// The full extraction expression is pinned, not the bare key: the
// query's result alias (total_runtime_ms) contains "runtime_ms", so a
// bare-key assertion would keep passing after the ->> key was renamed.
for field := range (usagetypes.HBAgentRuntime{}).Fields() {
require.Contains(t, getTotalUsageHBAgentRuntimeV1,
"event_data->>'"+field+"'")
}
}
Loading
Loading