11import { db } from '@sim/db'
2- import { subscription , user , workflowExecutionLogs , workspace } from '@sim/db/schema'
2+ import { subscription , workflowExecutionLogs , workspace } from '@sim/db/schema'
33import { createLogger } from '@sim/logger'
44import { and , eq , inArray , isNull , lt } from 'drizzle-orm'
55import { type NextRequest , NextResponse } from 'next/server'
@@ -26,38 +26,26 @@ export async function GET(request: NextRequest) {
2626 const retentionDate = new Date ( )
2727 retentionDate . setDate ( retentionDate . getDate ( ) - Number ( env . FREE_PLAN_LOG_RETENTION_DAYS || '7' ) )
2828
29- const freeUsers = await db
30- . select ( { userId : user . id } )
31- . from ( user )
29+ /**
30+ * Subquery: workspace IDs whose billed account user has no active paid
31+ * subscription. Kept as a subquery (not materialized into JS) so the
32+ * generated SQL is `WHERE workspace_id IN (SELECT ...)` — this avoids
33+ * PostgreSQL's 65535 bind-parameter limit that was breaking cleanup once
34+ * the free-user count grew beyond ~65k.
35+ */
36+ const freeWorkspacesSubquery = db
37+ . select ( { id : workspace . id } )
38+ . from ( workspace )
3239 . leftJoin (
3340 subscription ,
3441 and (
35- eq ( user . id , subscription . referenceId ) ,
42+ eq ( subscription . referenceId , workspace . billedAccountUserId ) ,
3643 inArray ( subscription . status , ENTITLED_SUBSCRIPTION_STATUSES ) ,
3744 sqlIsPaid ( subscription . plan )
3845 )
3946 )
4047 . where ( isNull ( subscription . id ) )
4148
42- if ( freeUsers . length === 0 ) {
43- logger . info ( 'No free users found for log cleanup' )
44- return NextResponse . json ( { message : 'No free users found for cleanup' } )
45- }
46-
47- const freeUserIds = freeUsers . map ( ( u ) => u . userId )
48-
49- const workspacesQuery = await db
50- . select ( { id : workspace . id } )
51- . from ( workspace )
52- . where ( inArray ( workspace . billedAccountUserId , freeUserIds ) )
53-
54- if ( workspacesQuery . length === 0 ) {
55- logger . info ( 'No workspaces found for free users' )
56- return NextResponse . json ( { message : 'No workspaces found for cleanup' } )
57- }
58-
59- const workspaceIds = workspacesQuery . map ( ( w ) => w . id )
60-
6149 const results = {
6250 enhancedLogs : {
6351 total : 0 ,
@@ -83,7 +71,7 @@ export async function GET(request: NextRequest) {
8371 let batchesProcessed = 0
8472 let hasMoreLogs = true
8573
86- logger . info ( ` Starting enhanced logs cleanup for ${ workspaceIds . length } workspaces` )
74+ logger . info ( ' Starting enhanced logs cleanup for free-plan workspaces' )
8775
8876 while ( hasMoreLogs && batchesProcessed < MAX_BATCHES ) {
8977 const oldEnhancedLogs = await db
@@ -105,7 +93,7 @@ export async function GET(request: NextRequest) {
10593 . from ( workflowExecutionLogs )
10694 . where (
10795 and (
108- inArray ( workflowExecutionLogs . workspaceId , workspaceIds ) ,
96+ inArray ( workflowExecutionLogs . workspaceId , freeWorkspacesSubquery ) ,
10997 lt ( workflowExecutionLogs . createdAt , retentionDate )
11098 )
11199 )
0 commit comments