@@ -10,11 +10,14 @@ import { enterpriseIssuanceOutboxHandlers } from '@/lib/billing/enterprise-provi
1010import { membershipBillingOutboxHandlers } from '@/lib/billing/organizations/membership-reconciliation'
1111import { billingOutboxHandlers } from '@/lib/billing/webhooks/outbox-handlers'
1212import { processOutboxEvents } from '@/lib/core/outbox/service'
13+ import { DeadlineExceededError } from '@/lib/core/utils/deadline'
1314import { generateRequestId } from '@/lib/core/utils/request'
1415import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
1516import { directGrantOutboxHandlers } from '@/lib/invitations/direct-grant'
1617import { slackSearchOutboxHandlers } from '@/lib/knowledge/application/slack-search/outbox'
18+ import { getConnectorFailureDiagnostic } from '@/lib/knowledge/connectors/connector-error'
1719import { knowledgeDocumentProcessingOutboxHandlers } from '@/lib/knowledge/documents/processing-outbox-handler'
20+ import { recoverKnowledgeDocumentProcessing } from '@/lib/knowledge/documents/processing-recovery'
1821import { organizationResourceCleanupOutboxHandlers } from '@/lib/organizations/resource-cleanup'
1922import { workspaceFileLiveDocOutboxHandlers } from '@/lib/uploads/contexts/workspace/workspace-file-live-doc-outbox'
2023import { workspaceFileStorageCleanupOutboxHandlers } from '@/lib/uploads/contexts/workspace/workspace-file-storage-cleanup-outbox'
@@ -53,12 +56,31 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
5356 return authError
5457 }
5558
59+ const startedAt = Date . now ( )
5660 const result = await processOutboxEvents ( handlers , {
5761 batchSize : 500 ,
58- maxRuntimeMs : 790_000 ,
62+ maxRuntimeMs : 760_000 ,
5963 minRemainingMs : 95_000 ,
6064 } )
6165
66+ let recoveredDocuments = 0
67+ try {
68+ if ( Date . now ( ) - startedAt < 770_000 ) {
69+ recoveredDocuments = await recoverKnowledgeDocumentProcessing ( )
70+ }
71+ } catch ( error ) {
72+ logger . error ( 'Stored document recovery failed' , {
73+ requestId,
74+ error : getConnectorFailureDiagnostic ( error ) ?? {
75+ category : error instanceof DeadlineExceededError ? 'deadline' : 'internal' ,
76+ message :
77+ error instanceof DeadlineExceededError
78+ ? error . message
79+ : 'Unexpected stored-document recovery failure' ,
80+ } ,
81+ } )
82+ }
83+
6284 // Reap fork background-work rows stuck `processing` past their TTL (worker crash /
6385 // restart has no in-task hook). Independent of the outbox; a failure here must not
6486 // fail the outbox run, so it's guarded separately.
@@ -69,13 +91,19 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
6991 logger . error ( 'Background-work reap failed' , { requestId, error : toError ( error ) . message } )
7092 }
7193
72- logger . info ( 'Outbox processing completed' , { requestId, ...result , reapedBackgroundWork } )
94+ logger . info ( 'Outbox processing completed' , {
95+ requestId,
96+ ...result ,
97+ reapedBackgroundWork,
98+ recoveredDocuments,
99+ } )
73100
74101 return NextResponse . json ( {
75102 success : true ,
76103 requestId,
77104 result,
78105 reapedBackgroundWork,
106+ recoveredDocuments,
79107 } )
80108 } catch ( error ) {
81109 logger . error ( 'Outbox processing failed' , { requestId, error : toError ( error ) . message } )
0 commit comments