Skip to main content
Jobs in Bull transition through various states during their lifecycle. These methods allow you to query and manipulate job state.

Status Check Methods

Bull provides convenience methods to check if a job is in a specific state. These methods are more efficient than calling getState() and comparing the result.

isCompleted()

isCompleted(): Promise<boolean>
Returns a promise resolving to true if the job’s state is completed.
const job = await queue.getJob(jobId);
if (await job.isCompleted()) {
  console.log('Job completed:', job.returnvalue);
}

isFailed()

isFailed(): Promise<boolean>
Returns a promise resolving to true if the job’s state is failed.
const job = await queue.getJob(jobId);
if (await job.isFailed()) {
  console.log('Job failed:', job.failedReason);
  await job.retry();
}

isDelayed()

isDelayed(): Promise<boolean>
Returns a promise resolving to true if the job’s state is delayed.
const job = await queue.getJob(jobId);
if (await job.isDelayed()) {
  console.log('Job scheduled to run later');
}

isActive()

isActive(): Promise<boolean>
Returns a promise resolving to true if the job’s state is active (currently being processed).
const job = await queue.getJob(jobId);
if (await job.isActive()) {
  console.log('Job is currently processing');
}

isWaiting()

isWaiting(): Promise<boolean>
Returns a promise resolving to true if the job’s state is waiting (queued for processing).
const job = await queue.getJob(jobId);
if (await job.isWaiting()) {
  console.log('Job is in the queue');
}

isPaused()

isPaused(): Promise<boolean>
Returns a promise resolving to true if the job’s state is paused.
const job = await queue.getJob(jobId);
if (await job.isPaused()) {
  console.log('Job is paused');
}

isStuck()

isStuck(): Promise<boolean>
Returns a promise resolving to true if the job’s state is stuck.
const job = await queue.getJob(jobId);
if (await job.isStuck()) {
  console.log('Job is stuck and may need attention');
}

Example: Comprehensive State Checking

async function checkJobStatus(jobId) {
  const job = await queue.getJob(jobId);
  
  if (await job.isCompleted()) {
    return { status: 'completed', result: job.returnvalue };
  } else if (await job.isFailed()) {
    return { status: 'failed', error: job.failedReason };
  } else if (await job.isActive()) {
    return { status: 'processing', progress: job.progress() };
  } else if (await job.isWaiting()) {
    return { status: 'queued' };
  } else if (await job.isDelayed()) {
    return { status: 'scheduled' };
  } else if (await job.isPaused()) {
    return { status: 'paused' };
  } else if (await job.isStuck()) {
    return { status: 'stuck' };
  }
  
  return { status: 'unknown' };
}

getState()

getState(): Promise<JobStatus>
Returns a promise resolving to the current job’s status.
state
string
Possible values: completed, failed, delayed, active, waiting, paused, stuck, or null
The implementation of this method is not very efficient, nor is it atomic. If your queue has a very large quantity of jobs, you may want to avoid using this method frequently.

Checking Job State

const job = await queue.getJob(jobId);
const state = await job.getState();

console.log(`Job is currently: ${state}`);

if (state === 'failed') {
  console.log('Job failed:', job.failedReason);
  await job.retry();
} else if (state === 'completed') {
  console.log('Job completed with result:', job.returnvalue);
}

State-Based Logic

async function handleJob(jobId) {
  const job = await queue.getJob(jobId);
  const state = await job.getState();
  
  switch (state) {
    case 'waiting':
    case 'delayed':
      console.log('Job is queued');
      break;
    case 'active':
      console.log('Job is currently processing');
      break;
    case 'completed':
      console.log('Job finished successfully');
      break;
    case 'failed':
      console.log('Job failed, retrying...');
      await job.retry();
      break;
    default:
      console.log('Unknown state:', state);
  }
}

update()

update(data: object): Promise
Updates a job’s data field with the given data object.
data
object
required
The new data object to replace job.data

Updating Job Data

const job = await queue.add({ status: 'pending', items: [] });

// Later, update the job data
await job.update({
  status: 'in-progress',
  items: ['item1', 'item2', 'item3']
});

console.log(job.data);
// { status: 'in-progress', items: ['item1', 'item2', 'item3'] }

Dynamic Job Updates

queue.process(async (job) => {
  // Fetch additional data during processing
  const additionalData = await fetchExtraData(job.data.id);
  
  // Update job with new data
  await job.update({
    ...job.data,
    additionalData: additionalData
  });
  
  // Continue processing with updated data
  return processWithData(job.data);
});
Updating job data does not change the job’s state or restart processing. It only updates the job.data field.

moveToCompleted()

moveToCompleted(returnValue: any, ignoreLock: boolean, notFetch?: boolean): Promise<[string, string] | null>
Moves a job to the completed queue. Pulls a job from ‘waiting’ to ‘active’ and returns a tuple containing the next job’s data and id.
returnValue
any
required
The value to set as the job’s return value
ignoreLock
boolean
required
Whether to ignore the job lock
notFetch
boolean
Set to true to avoid prefetching the next job in the queue
return
[string, string] | null
Tuple of [nextJobData, nextJobId] or null if no job is waiting
This is a low-level method. In most cases, you should return a value from your processor function instead of calling this method directly.

Manual Completion

queue.process(async (job) => {
  // Custom processing logic
  const result = await customProcess(job.data);
  
  // Manually move to completed
  await job.moveToCompleted(result, false);
  
  // Note: You typically wouldn't do this - just return the result instead
});

moveToFailed()

moveToFailed(errorInfo: { message: string }, ignoreLock?: boolean): Promise<[string, string] | null>
Moves a job to the failed queue. Pulls a job from ‘waiting’ to ‘active’ and returns a tuple containing the next job’s data and id.
errorInfo
object
required
Object containing error information
ignoreLock
boolean
Whether to ignore the job lock
return
[string, string] | null
Tuple of [nextJobData, nextJobId] or null if no job is waiting
This is a low-level method. In most cases, you should throw an error from your processor function instead of calling this method directly.

Manual Failure

queue.process(async (job) => {
  const validation = validateJob(job.data);
  
  if (!validation.valid) {
    // Manually move to failed
    await job.moveToFailed({
      message: `Validation failed: ${validation.error}`
    }, false);
    return;
  }
  
  // Continue processing...
  
  // Note: You typically wouldn't do this - just throw an error instead
});
Instead of using moveToCompleted() and moveToFailed() directly:
queue.process(async (job) => {
  // Validate
  if (!isValid(job.data)) {
    throw new Error('Invalid job data');
  }
  
  // Process
  const result = await processJob(job.data);
  
  // Return result (Bull handles moveToCompleted internally)
  return result;
});

Build docs developers (and LLMs) love