11import 'server-only' ;
22
33import { addDays , addHours } from 'date-fns' ;
4- import { and , eq , inArray , lte , sql } from 'drizzle-orm' ;
4+ import { and , asc , eq , inArray , lte , sql } from 'drizzle-orm' ;
55import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js' ;
66
77import { maybePerformAutoTopUp } from '@/lib/autoTopUp' ;
@@ -20,6 +20,7 @@ import type * as schema from '@kilocode/db/schema';
2020
2121const logInfo = sentryLogger ( 'coding-plans-billing-cron' , 'info' ) ;
2222const logError = sentryLogger ( 'coding-plans-billing-cron' , 'error' ) ;
23+ const BILLING_LIFECYCLE_SWEEP_LIMIT = 1_000 ;
2324
2425export type CodingPlanCronSummary = {
2526 renewals : number ;
@@ -111,7 +112,9 @@ async function sweepCancelAtPeriodEnd(
111112 eq ( coding_plan_subscriptions . cancel_at_period_end , true ) ,
112113 lte ( coding_plan_subscriptions . current_period_end , nowIso )
113114 )
114- ) ;
115+ )
116+ . orderBy ( asc ( coding_plan_subscriptions . current_period_end ) , asc ( coding_plan_subscriptions . id ) )
117+ . limit ( BILLING_LIFECYCLE_SWEEP_LIMIT ) ;
115118
116119 for ( const row of rows ) {
117120 try {
@@ -196,7 +199,9 @@ async function sweepRenewals(
196199 eq ( coding_plan_subscriptions . cancel_at_period_end , false ) ,
197200 lte ( coding_plan_subscriptions . credit_renewal_at , nowIso )
198201 )
199- ) ;
202+ )
203+ . orderBy ( asc ( coding_plan_subscriptions . credit_renewal_at ) , asc ( coding_plan_subscriptions . id ) )
204+ . limit ( BILLING_LIFECYCLE_SWEEP_LIMIT ) ;
200205
201206 for ( const selectedRow of rows ) {
202207 const row : RenewalRow = {
@@ -260,6 +265,9 @@ async function processRenewal(
260265 selectedRow : RenewalRow ,
261266 nowIso : string
262267) : Promise < RenewalResult > {
268+ // Renewal processing has one durable outcome per due term, guarded by row locks
269+ // and an idempotency key: charge and extend, start a single auto-top-up grace
270+ // window, wait for in-flight grace recovery, or terminate and queue revocation.
263271 return database . transaction ( async tx => {
264272 await tx . execute (
265273 sql `SELECT id FROM coding_plan_subscriptions WHERE id = ${ selectedRow . id } FOR UPDATE`
0 commit comments