What all customers want: A Job Queue Restarter

What if we could get Job Queue entries stuck in Error state, restarted without anything going into the Job Queue and click restart? Check out the video:

https://youtu.be/H0wR2BJNaVs

In this video, Erik walks through a solution he’s built for countless customers over the years: an automatic Job Queue Restarter for Business Central. If you’ve ever had job queue entries fail and needed to manually go in and restart them, this small but mighty app will save you time and frustration.

The Problem: Failed Job Queues Need Manual Restarts

A common scenario in Business Central is having job queue entries that fail due to transient errors — a lost database connection, a CRM synchronization hiccup, or some other temporary issue. When this happens, the job enters an “Error” state and just sits there. Someone has to manually navigate to the Job Queue Entries page, find the failed job, and set it back to “Ready” so it can run again.

As Erik demonstrates, this is tedious. He shows an “unreliable” job that keeps failing, and each time he has to go in, set it to Ready, only for it to fail again. The fix? Automate the restart process entirely.

Key Design Decision: Keep It in a Separate App

Before diving into the code, Erik emphasizes an important architectural decision: always deploy the job queue restarter as its own standalone app, separate from your other extensions.

Why? During app deployment, if the restarter’s job queue entry fires while the app it lives in is being updated, it can encounter errors like “this codeunit does not exist” because the code is mid-deployment. If the restarter itself goes into an error state, you’d need a restarter for your restarter — an infinite loop of pain. Keeping it isolated in its own app avoids this problem entirely.

The Code: Surprisingly Simple

The entire solution is a single codeunit. Here’s the final version:

codeunit 54600 "Job Queue Restarter"
{
    TableNo = "Job Queue Entry";
    trigger OnRun()
    var
        JQ: Record "Job Queue Entry";
    begin
        JQ.Setrange(Status, JQ.Status::Error);
        JQ.SetFilter("Object ID to Run", Rec."Parameter String");
        if JQ.FindSet() then
            repeat
                JQ.Restart();
            until JQ.Next() = 0;
    end;
}

Let’s break down what’s happening:

  1. TableNo = “Job Queue Entry” — This tells Business Central that this codeunit operates on the Job Queue Entry table, which means it can accept a parameter string when configured as a job queue entry itself.
  2. Filter for errorsJQ.SetRange(Status, JQ.Status::Error) finds all job queue entries currently in an error state.
  3. Filter by Object IDJQ.SetFilter("Object ID to Run", Rec."Parameter String") allows you to specify which specific jobs to monitor. You pass a filter expression (e.g., specific object IDs) through the job queue’s Parameter String field, so you can target only certain jobs rather than blindly restarting everything.
  4. Restart each one — The JQ.Restart() function is a built-in method on the Job Queue Entry record that conveniently handles setting the job back to a ready state.

Erik points out that the Restart() function is one of several “very convenient” built-in functions on the Job Queue Entry record — no need to manually manipulate status fields.

The App Manifest

The app.json is kept minimal, as you’d expect for a utility app like this:

{
  "id": "9bd96851-0dd2-4c98-8d3a-a4a982e89ebb",
  "name": "JobRestarter",
  "publisher": "Erik Hougaard",
  "version": "1.0.0.0",
  "dependencies": [],
  "platform": "1.0.0.0",
  "application": "21.0.0.0",
  "idRanges": [
    {
      "from": 54600,
      "to": 54649
    }
  ],
  "runtime": "10.0",
  "features": [
    "NoImplicitWith"
  ]
}

No dependencies, no frills — just a self-contained restarter app.

Setting It Up

Once deployed, you create a new Job Queue Entry that runs this codeunit. Set it to run on a recurring schedule (e.g., every few minutes), and it will automatically find and restart any failed jobs matching your filter criteria. You can then check the log entries to see when and what it restarted.

Possible Enhancements

Erik mentions several ways you could extend this basic pattern:

  • Selective restarting — Use the Parameter String to filter which Object IDs to restart, so you only auto-restart specific jobs while leaving others in their error state for manual investigation.
  • Email notifications — Add notification logic so someone gets alerted when a job has been automatically restarted.
  • Logging and monitoring — Enhance the logging to track how often jobs are failing and being restarted, which could indicate a deeper underlying issue.

Real-World Use Cases

Erik notes that this pattern is especially valuable for CRM integrations and data synchronization scenarios. When a connection to an external database drops momentarily, your replication or synchronization job stops, and suddenly you’re missing customers, orders, or other critical data. An automatic restarter ensures these processes recover quickly without human intervention.

Conclusion

In roughly 13 lines of AL code and a standalone app, you can build a reliable job queue restarter that saves you and your customers from the tedious manual process of monitoring and restarting failed jobs. The key takeaways are: keep it in its own app to avoid deployment conflicts, use the built-in Restart() function on the Job Queue Entry record, and consider filtering by Object ID so you only restart the jobs that truly need automatic recovery.