We’re experiencing an issue with our serverless API route that handles reminder emails. Despite implementing safety checks that should prevent reminders from being sent more frequently than every 12 hours, we continue to see reminders being sent at much shorter intervals in our production environment. The same code works correctly in our local development environment.
The endpoint processes reminder eligibility with safety checks that prevent any reminders from being sent to the same recipient more frequently than every 12 hours
The safety check code looks like this:
// SAFETY CHECK: Enforce minimum time between reminders regardless of other logic
if (sme.last_reminder_sent) {
const lastSent = new Date(sme.last_reminder_sent);
const now = new Date();
const hoursSinceLastReminder = (now.getTime() - lastSent.getTime()) / (1000 * 60 * 60);
// Minimum 12 hours between any reminders as a safety measure
const MINIMUM_HOURS_BETWEEN_REMINDERS = 12;
if (hoursSinceLastReminder < MINIMUM_HOURS_BETWEEN_REMINDERS) {
// Block reminder and log the block
return {
success: false,
projectId: project.id,
smeId: sme.sme_id,
reminderType: null,
message: `Safety check: Only ${Math.round(hoursSinceLastReminder)} hours since last reminder (minimum: ${MINIMUM_HOURS_BETWEEN_REMINDERS})`
};
}
}
Actual Behavior:
In production, reminders are being sent much more frequently (every 3-6 hours)
Local testing confirms the safety check is working properly
Database records show the last_reminder_sent field is being updated correctly
Our enhanced logging (using console.error) shows the safety checks are working locally
Could multiple concurrent executions of the same serverless function be occurring in Vercel, bypassing our safety checks?
Is there a caching issue where stale data is being used in subsequent function executions?
Are serverless functions in Vercel potentially running with different timestamps/timezones than expected?
Could there be issues with database connection pooling or transaction isolation that’s causing race conditions?
Is there a way to better debug or trace the execution of this function in the Vercel environment?
Anything else?
Additional info
We’re using Supabase for our database
Our development environment is Next.js 14
We don’t see any relevant errors in the Vercel Function logs
The issue seemed to start recently without code changes in this area
We’d appreciate any insights or debugging suggestions to help resolve this production-only issue. Please let us know what additional information you might need.
Hi, I’ve checked my configuration and can confirm I don’t have trailingSlash set in next.config.js (which i believe defaults to false).
My cron job path is set to /api/reminders which matches my API route
My middleware explicitly excludes API routes from processing.
I’ve also observed 404 cache errors in the logs i shared earlier.
Could the 308 redirects be coming from Vercel’s edge network or Next.js’ internal handling? What I’m primarily concerned about is that reminders are being sent too frequently despite safety checks in my code.
We confirmed a potential 308 redirect issue: Our cron job is correctly configured with ‘/api/reminders’ (no trailing slash)
However, testing shows that if a trailing slash is added (making it ‘/api/reminders/’), a 308 redirect occurs
Your documentation notes that “cron jobs do not follow redirects”
This suggests that occasionally Vercel’s system might be adding a trailing slash despite our correct configuration
Steps we’ve taken:
Added comprehensive Cache-Control headers to the endpoint code to prevent caching
This shouldn’t be happening. If you have a reproducible steps, please share with us so we can take a look.
The 404 cache errors you’re seeing (where ‘GET Using cache’ is followed by a 404) are not necessarily expected behavior. This could indicate a few different issues:
Cached responses: When cron jobs respond with a cached response, they might not show up properly in logs . This could explain the ‘Using cache’ message.
Nonexistent paths: If your cron job is configured for a path that doesn’t exist, it will generate a 404 error, but Vercel will still execute the job.
Thought for 4 seconds### Understanding 404 Cache Errors in Cron Jobs
The 404 cache errors you’re seeing (where ‘GET Using cache’ is followed by a 404) are not necessarily expected behavior. This could indicate a few different issues:
Cached responses: When cron jobs respond with a cached response, they might not show up properly in logs . This could explain the ‘Using cache’ message.
Nonexistent paths: If your cron job is configured for a path that doesn’t exist, it will generate a 404 error, but Vercel will still execute the job .
Making Cron Jobs More Reliable
To improve the reliability of your cron jobs:
Secure your cron jobs: Add a CRON_SECRET environment variable and verify it in your endpoint:
export function GET(request: NextRequest) {
const authHeader = request.headers.get('authorization');
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return new Response('Unauthorized', { status: 401 });
}
// Your cron job logic here
return Response.json({ success: true });
}
Implement concurrency control: If your cron jobs take too long to run, you might have concurrent invocations. Consider implementing a lock mechanism (e.g., using Redis) .
Error handling: Vercel won’t retry failed cron jobs, so implement robust error handling in your code .
Check logs: Use the “View Logs” button in the Cron Jobs tab to diagnose issues .
For Edge routes triggered by cron jobs:
Be aware of duration limits: Edge functions have duration limits similar to Serverless functions. If you need more processing time, consider splitting your workload .
Handle redirects properly: Cron jobs don’t follow redirects. When a cron-triggered endpoint returns a 3xx status code, the job completes without following the redirect .
Data caching: Verify whether your data requests are being cached appropriately. For Edge routes, ensure you’re using proper caching strategies .
Error boundaries: Implement error handling to gracefully handle failures .
Dynamic rendering considerations: Be mindful that using dynamic APIs will opt your route into Dynamic Rendering, which could affect performance .
Streaming responses: Consider using streaming for long-running processes to improve user experience .
To debug your specific 404 cache errors, I recommend checking your logs and verifying that the paths in your cron job configuration actually exist in your application.