Job Queue
In Dynamics NAV 2013, you can setup job queue to automate processing of tasks. Popular tasks that are automated are things such as Adjust Cost – Item Entries, EDI processing, Reporting, etc.
Setting up job queue in NAV2013 couldn’t be much easier can a step by step instruction can be found here.
The Problem
When the job queue runs into an error, it will never get picked up again. This means that while the Job Queue is an automated process, the IT manager will need to monitor this every day to make sure every process is running.
I know what you’re thinking, “This does not make sense!”. I fully agree.
There are some processes where the error is fatal. This is the reason why you would not want to have it run again. However, there are some situations where the error occurs when the table is locked by another process, in this case, you absolutely need to have it restart again.
This is especially true when you process EDI orders. You have to send back acknowledgment and/or confirmation within a certain timeframe or else you’ll get charge backs. Having the job queue error out because of table locks does not make too much sense.
The Solution
The problem lies in the Job Queue Dispatcher codeunit (448). If you go down and find the local function GetNextRequest, you’ll see that for some odd reason, the process is only looking at any statuses that are Ready.So we will need to modify the code to scan for the error entries as well.
Depending on what you use the Job Queue for, I would include job queues that are In Process. The reason is if it’s running and someone stops the job queue, it’ll stay stuck in the In Process status.
By setting this, it’s important that you set the Max No. of Attempts. You don’t want the job queue to keep running if there really is a critical error.
A special thanks to Rafael Rezende for helping me with this!
Hi Alex, hi Rafael,
tanks for sharing this. The interesting part of this behaviour change is that GetNextRequest has always only looked at ready queue entries (just checked in mercurial). I concur that also filtering on “error” would be sensible. The HandleRequest() function of old has reset the status to ready after an unsuccesful attempt (and sufficient retries remaining). As HandleRequest() was timer-based, there was a delay of at least 2 seconds before the next retry. This is effectively the same checking for the error state, without allowing the “unwanted” errors to reoccur.
The heart of the change appears to be in the completely changed handling of the jobs to run. They run in a concurrent session, and the retries run in the same session consecutively, without much delay, as it seems. And (worse) without logging the errors of the unsuccessful attempts – only the last unsuccessful attempt appears to be logged. Go figure.
with best regards
Jens
I would say another approach is run schedule a separate job that checks the jobs and changes the status. This way you can control how ofter it runs and when to run and also not to reset the status if it’s the same error more than once or twice etc.
Fantastic, thanks for sharing. Shows again how one line of code can make a big difference. I had modified the Job Queue Entry table so that it sends me a mail every time a queue status changes to error. Now with this change I don’t need to freak out every time I receive the email when on holiday!
Hello Bruce
Could you please share your code that mails upon error on the job queue. Many thanks!
Hi, Here is my example where I have added 2 fields to the Jobqueue entry table and page, to allow an email to be sent when job failed.
Here is the code for the Procedure: UpdateLogEntry
LOCAL UpdateLogEntry(LogEntryNo : Integer;VAR JobQueueEntry : Record “Job Queue Entry”)
IF JobQueueLogEntry.GET(LogEntryNo) THEN BEGIN
JobQueueLogEntry.”End Date/Time” := CURRENTDATETIME;
IF JobQueueEntry.Status = JobQueueEntry.Status::Error THEN BEGIN
JobQueueLogEntry.Status := JobQueueLogEntry.Status::Error;
JobQueueLogEntry.SetErrorMessage(JobQueueEntry.GetErrorMessage);
//>>AB7.02.01
IF JobQueueEntry.”Notify On Error” THEN BEGIN
IF JobQueueEntry.”Notify e-mail” ” THEN
SMTPMail.CreateMessage(USERID,’error@company.dk’,JobQueueEntry.”Notify e-mail”,STRSUBSTNO(‘JOb Queueø:%1 failedt’,JobQueueLogEntry.Description),
STRSUBSTNO(‘JobQueue:%1,Start time:%2%3’,JobQueueLogEntry.Description,JobQueueLogEntry.”Start Date/Time”,JobQueueLogEntry.”Error Message”),TRUE);
SMTPMail.Send;
END;
//<<AB7.02.01
END ELSE
JobQueueLogEntry.Status := JobQueueLogEntry.Status::Success;
JobQueueLogEntry.MODIFY;
END
Thank you for sharing your code Morten!
Hi Alex,
Have you set up the Job Queue to proactively notify you via e-mail if it errors out?
Yep. With the SMTP Mail (codeunit 400), you can practically send any types of e-mails under any condition.
There is another error that this will not pickup. Example a job which runs and usually takes 10 minutes to run.
when it runs it can sometimes then have the status of “In Progress” but actually be in error. It will have a start time to it but no end time, even several hours later.
You can change the filter to include in progress as well. I would caution against doing this however. Typically, if a process runs into an error, it will error out on the job queue.
Thank you guys for the tip.
Here is a slight modification for NAV 2016 and fix for the Morten’s mod to UpdateLogEntry.
TAB 472 Job Queue Entry
50000 Notify on Error Boolean
50001 Notify E-Mail Text 250
50002 Run After Error Boolean
COD 448 Job Queue Dispatcher
LOCAL GetNextRequest(VAR JobQueueEntry : Record “Job Queue Entry”) : Boolean
JobQueueEntry.LOCKTABLE;
JobQueueEntry.SETFILTER(“Expiration Date/Time”,’>%1|%2′,CURRENTDATETIME,CREATEDATETIME(0D,0T));
JobQueueEntry.SETFILTER(“Earliest Start Date/Time”,'<=%1',CURRENTDATETIME);
IF JobQueue."Job Queue Category Filter" ” THEN
JobQueueEntry.SETFILTER(“Job Queue Category Code”,JobQueue.”Job Queue Category Filter”);
//>>
//JobQueueEntry.SETRANGE(Status,JobQueueEntry.Status::Ready);
JobQueueEntry.SETFILTER(Status,’%1|%2′,JobQueueEntry.Status::Ready,JobQueueEntry.Status::Error);
JobQueueEntry.SETCURRENTKEY(Priority);
JobQueueEntry.LOCKTABLE;
//Found := TryFindNextJobQueueEntry(JobQueueEntry) AND (JobQueueEntry.Status = JobQueueEntry.Status::Ready);
Found := TryFindNextJobQueueEntry(JobQueueEntry) AND ((JobQueueEntry.Status = JobQueueEntry.Status::Ready)
OR ((JobQueueEntry.Status = JobQueueEntry.Status::Error) AND (JobQueueEntry.”Run After Error”)));
//<>
IF JobQueueEntry.”Notify on Error” THEN
IF JobQueueEntry.”Notify E-Mail” ” THEN
IF SMTPMailSetup.GET() THEN BEGIN
SMTPMail.CreateMessage( COMPANYNAME +’ | Job Queue – ‘+ JobQueueEntry.”Object Caption to Run”,
SMTPMailSetup.”User ID”,
JobQueueEntry.”Notify E-Mail”,
STRSUBSTNO(‘Job Queue %1 Failed’,JobQueueLogEntry.Description),
STRSUBSTNO(‘JobQueue: %1Start time: %2Failed With Error: %3’, JobQueueLogEntry.Description, JobQueueLogEntry.”Start Date/Time”, JobQueueLogEntry.”Error Message”),
TRUE);
SMTPMail.Send;
END;
//<<
END ELSE
JobQueueLogEntry.Status := JobQueueLogEntry.Status::Success;
JobQueueLogEntry.MODIFY;
END;
Thank you for sharing the code!
How do I make changes in NAV 2017 because I didn’t found any GetNextRequest function please suggest.
This part is completely re-written in NAV2017. You’ll need to ask your NAV partner to do this mod for you.