Skip to content

Commit 938b0a9

Browse files
fix(billing): always warn on userStats drift in recordUsage
1 parent 8e5305b commit 938b0a9

1 file changed

Lines changed: 13 additions & 5 deletions

File tree

apps/sim/lib/billing/core/usage-log.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,13 @@ export interface RecordUsageParams {
7575
*
7676
* The two writes are intentionally not wrapped in a transaction: under high
7777
* concurrency for the same userId, holding BEGIN/COMMIT across the user_stats
78-
* row-lock wait pins pgbouncer connections and exhausts the pool. usage_log
79-
* is the source of truth; if the userStats UPDATE fails the counter drifts
80-
* and must be reconciled from usage_log out-of-band.
78+
* row-lock wait pins pgbouncer connections and exhausts the pool.
79+
*
80+
* usage_log is the source of truth and the INSERT propagates errors to the
81+
* caller. The userStats UPDATE is best-effort: failures (and missing-row
82+
* cases) are logged as warnings and swallowed. Counter drift is acceptable
83+
* here — the long-term plan is to derive counters from usage_log directly.
84+
* Any drift warning in logs is a signal that needs investigation.
8185
*/
8286
export async function recordUsage(params: RecordUsageParams): Promise<void> {
8387
if (!isBillingEnabled) {
@@ -135,16 +139,20 @@ export async function recordUsage(params: RecordUsageParams): Promise<void> {
135139
.returning({ userId: userStats.userId })
136140

137141
if (result.length === 0) {
138-
logger.warn('recordUsage: userStats row not found; counter will drift from usage_log', {
142+
logger.warn('recordUsage: userStats row not found; counter increment dropped', {
139143
userId,
140144
totalCost,
145+
hadEntries: validEntries.length > 0,
146+
additionalStatsKeys: safeStats ? Object.keys(safeStats) : [],
141147
})
142148
}
143149
} catch (error) {
144-
logger.error('recordUsage: userStats update failed; counter will drift from usage_log', {
150+
logger.warn('recordUsage: userStats update failed; counter increment dropped', {
145151
error: toError(error).message,
146152
userId,
147153
totalCost,
154+
hadEntries: validEntries.length > 0,
155+
additionalStatsKeys: safeStats ? Object.keys(safeStats) : [],
148156
})
149157
}
150158

0 commit comments

Comments
 (0)