DataQueueDataQueue
Usage

Reclaim Jobs

Running a long-lived server? Use createSupervisor() to automate stuck-job reclaiming instead of calling reclaimStuckJobs manually.

Sometimes, a job can get stuck in the processing state. This usually happens if the process is killed or an unhandled error occurs after the job status is updated, but before it is marked as completed or failed.

To recover stuck jobs, use the reclaimStuckJobs method. The example below shows how to create an API route (/api/cron/reclaim) that can be triggered by a cron job:

@/app/api/cron/reclaim.ts
import { getJobQueue } from '@/lib/queue';
import { NextResponse } from 'next/server';

export async function GET(request: Request) {
  // Secure the cron route: https://vercel.com/docs/cron-jobs/manage-cron-jobs#securing-cron-jobs
  const authHeader = request.headers.get('authorization');
  if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
    return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });
  }

  try {
    const jobQueue = getJobQueue();

    // Reclaim jobs stuck for more than 10 minutes
    const reclaimed = await jobQueue.reclaimStuckJobs(10);
    console.log(`Reclaimed ${reclaimed} stuck jobs`);

    return NextResponse.json({
      message: 'Stuck jobs reclaimed',
      reclaimed,
    });
  } catch (error) {
    console.error('Error reclaiming jobs:', error);
    return NextResponse.json(
      { message: 'Failed to reclaim jobs' },
      { status: 500 },
    );
  }
}

Per-Job Timeout Awareness

reclaimStuckJobs respects each job's individual timeoutMs. If a job has a timeoutMs that is longer than maxProcessingTimeMinutes, it will not be reclaimed until its own timeout has elapsed. For example, if you call reclaimStuckJobs(10) and a job has timeoutMs: 1800000 (30 minutes), that job will only be reclaimed after 30 minutes — not 10.

Jobs without a timeoutMs continue to use the global maxProcessingTimeMinutes threshold as before.

Scheduling the Reclaim Job with Cron

Add the following to your vercel.json to call the cron route every 10 minutes:

vercel.json
{
  "crons": [
    {
      "path": "/api/cron/reclaim",
      "schedule": "*/10 * * * *"
    }
  ]
}