Compare commits

..

2 Commits

Author SHA1 Message Date
Vikhyath Mondreti
fdfa935a09 v0.3.38: billing cron job fix 2025-08-22 17:03:36 -07:00
Vikhyath Mondreti
917552f041 fix(billing): vercel cron not processing billing periods (#1112) 2025-08-22 16:52:31 -07:00
2 changed files with 54 additions and 11 deletions

View File

@@ -67,7 +67,7 @@ export async function POST(request: NextRequest) {
{ status: 500 }
)
} catch (error) {
logger.error('Fatal error in monthly billing cron job', { error })
logger.error('Fatal error in daily billing cron job', { error })
return NextResponse.json(
{
@@ -90,18 +90,59 @@ export async function GET(request: NextRequest) {
return authError
}
return NextResponse.json({
status: 'ready',
message:
'Daily billing check cron job is ready to process users and organizations with periods ending today',
currentDate: new Date().toISOString().split('T')[0],
const startTime = Date.now()
const result = await processDailyBillingCheck()
const duration = Date.now() - startTime
if (result.success) {
logger.info('Daily billing check (GET) completed successfully', {
processedUsers: result.processedUsers,
processedOrganizations: result.processedOrganizations,
totalChargedAmount: result.totalChargedAmount,
duration: `${duration}ms`,
})
return NextResponse.json({
success: true,
summary: {
processedUsers: result.processedUsers,
processedOrganizations: result.processedOrganizations,
totalChargedAmount: result.totalChargedAmount,
duration: `${duration}ms`,
},
})
}
logger.error('Daily billing check (GET) completed with errors', {
processedUsers: result.processedUsers,
processedOrganizations: result.processedOrganizations,
totalChargedAmount: result.totalChargedAmount,
errorCount: result.errors.length,
errors: result.errors,
duration: `${duration}ms`,
})
} catch (error) {
logger.error('Error in billing health check', { error })
return NextResponse.json(
{
status: 'error',
error: error instanceof Error ? error.message : 'Unknown error',
success: false,
summary: {
processedUsers: result.processedUsers,
processedOrganizations: result.processedOrganizations,
totalChargedAmount: result.totalChargedAmount,
errorCount: result.errors.length,
duration: `${duration}ms`,
},
errors: result.errors,
},
{ status: 500 }
)
} catch (error) {
logger.error('Fatal error in daily billing (GET) cron job', { error })
return NextResponse.json(
{
success: false,
error: 'Internal server error during daily billing check',
details: error instanceof Error ? error.message : 'Unknown error',
},
{ status: 500 }
)

View File

@@ -57,8 +57,10 @@ export async function verifyInternalToken(token: string): Promise<boolean> {
export function verifyCronAuth(request: NextRequest, context?: string): NextResponse | null {
const authHeader = request.headers.get('authorization')
const expectedAuth = `Bearer ${env.CRON_SECRET}`
const isVercelCron = request.headers.get('x-vercel-cron') === '1'
if (authHeader !== expectedAuth) {
// Allow Vercel Cron requests (they include x-vercel-cron header instead of Authorization)
if (!isVercelCron && authHeader !== expectedAuth) {
const contextInfo = context ? ` for ${context}` : ''
logger.warn(`Unauthorized CRON access attempt${contextInfo}`, {
providedAuth: authHeader,