How to force specific service instance in Task Scheduler in NAV 2017?

igor.chladiligor.chladil Member Posts: 28

Before NAV 2017 we had Job Queue table and in the job queue table it was possible to specify that some tasks must be running on a specific NAV service.
This was quite helpful feature e.g. in the following situations:
  1. Background printing - it was sufficient to configure printers only on one machine and pass the printing jobs via that machine
  2. Different user accessing SQL - if different NAV services had different service users, it was immediately visible in the SQL statements which service owned which request.
  3. Different permissions - it was possible to give different services different system permissions via its Service Account.

With Task Scheduler it seems we are missing the option of forcing specific host and/or service to take care about the scheduled task.
Could anybody please suggest if there is any workaround in which we could force certain tasks to run on specific services?

I am aware only about the following which I do not particularly like:
  1. Fire from Scheduled Task that task on a specific service using Web Services. But then the impersonation would not work :neutral: ...
  2. Use Old Job Queue instead of Task Scheduler.

Any suggestions on how to force specific service instance using Task Scheduler?

Also if you have some in-depth technical explanations on how NAV 2017 task scheduler works with multiple services are welcome. At the moment I take it so that the service to process the scheduled task is chosen somehow behind the scenes. But how that somehow works is less clear to me ...



  • Options
    RoelofRoelof Member Posts: 377
    I have the same question as Igor.
    Any ideas anyone?
    Roelof de Jonghttp://www.wye.com
  • Options
    HannesHolstHannesHolst Member Posts: 119
    edited 2017-03-29
    Hey there,

    As I understand the documentation, there is no "build in" option to handle this requirement.
    When Codeunit 448 is called, why not check the current sessionID with the sessionID of the desired ServiceTier?

    Thinking one step further, it is thinkable to create an additional dispatcher which calls a STARTSESSION with the desired SessionID.

  • Options
    OldNavDogOldNavDog Member Posts: 88
    Task Scheduler does not Create "Sessions" in the usual Sense, i.e. in the Active Session Table (2000000110); only "Session Events" in the Session Event Table (2000000111).

    Now if someone would only tell me how you DEBUG a Task Scheduler Task...
    Experience is what you get, when you don't get what you want. --Anon.
  • Options
    igor.chladiligor.chladil Member Posts: 28
    Hi Hannes,

    just a quick response to your suggestions - when Job Queue Dispatcher runs it already runs on a specific service instance and I am not aware about any way which would migrate that session to another service instance. I am not also aware about any way which would spawn a new session on another service instance (STARTSESSION happens on the same service instance).

    Former Job Queue method actually spawned job queue entries looping session on all the service instances where it was allowed. And that is why it could filter out its own job queue entries and start these on correct service instance using STARTSESSION.

    I however like Task Scheduler and I am missing this only bit - possibility to give it the hint about the service it should execute on.

    OldNavDog - you can debug scheduled task by using breakpoint & starting Debug Next. Scheduled Task fires the background session for the time needed for its execution.

  • Options
    HannesHolstHannesHolst Member Posts: 119

    Just stumbled across this topic in Google as I did a research for a similar topic :-)

    You could use something like the following to achieve the requirement.
    I didn't test it, but it should be starting point.

    1) store in the Job Queue the Server and Instance which you want to run the code in
    2) in your Dispatcher-Codeunit (for example 448) make something like this:
    // get current server instance
    IF ServerInstance."Service Name" <> JobQueueEntry."Server Instance to be executed on" THEN
    // check for current session
    IF SESSIONID <> JobQueueEntry."Session to be executed in" THEN
    ExecuteFunction(); // call Codeunit or Report as configured in Job Queue Entry here

    Additionally you could do something like this:
    // get current server instance
    IF ServerInstance."Service Name" <> JobQueueEntry."Service to be executed on" THEN
    // execute session directly
    STARTSESSION(JobQueueEntry."Session to be executed in",CODEUNIT::"whatever",COMPANYNAME,Rec);

    The Task Scheduler basically calls every time the same Codeunit (448 in standard config).
    Each of the NAS Services will go through the code and checks if the Server Name matches.
    If not, do nothing (make sure that the Execution DateTime of the Job Queue Entry will not be updated).
  • Options
    JuhlJuhl Member Posts: 724
    The workaround only solves job queue entries. Not Scheduled Task.
    Follow me on my blog juhl.blog
  • Options
    HannesHolstHannesHolst Member Posts: 119
    edited 2017-08-15
    @Juhl: Everytime you push "Set Status to Ready" for a Job Queue, a Scheduled Task will be created. If you have built your own solution, build a setup in NAV to identify the Scheduled Tasks and on which Server to run. Then implement the above code into the Codeunit your Scheduled Task executes.
  • Options
    vremeni4vremeni4 Member Posts: 323

    Did someone tried to use the table $ndo$taskscheduling on SQL to get a solution for this.
    The table does contain the field [Server Instance ID] and it gets updated but the entry does not "live" very long.
    So my idea would be to use SQL trigger to check before the entry is inserted and overwrite this this field with the "correct" value for [Server Instance ID] or similar.

  • Options
    JuhlJuhl Member Posts: 724
    Maybe you should design for the future.
    Using APIs, unc paths, Azure Files or what ever, one should never make a dependency on specific server, all above doesn’t care where it’s run!
    I never needed this in a profject!

    Think BC Online... here you can’t control anything!
    Follow me on my blog juhl.blog
  • Options
    RydenRyden Member Posts: 24
    Some installations will have to stay on prem and there is definitely a need of this functionality.
    We have a very big customer who does some heavy automated invoicing once a month.
    The job used to take +36h, by splitting the customers in half and running the job in parallell on two separate NSTs we've cut that down to 12h.
    They're scheduled for upgrade to 2018 and this is one of the major stumbling blocks.
  • Options
    RydenRyden Member Posts: 24
    We need to split this on two different servers, running both jobs on one server chokes it to death.
  • Options
    bertvangestelbertvangestel Member Posts: 1
    Just ran into this issue.

    Fixed it using Row level security on the sql server. If your 2 or more taskshedulers log into the sql server using different credentials you can make them only see the records for a specific company.


    CREATE FUNCTION fn_TaskShedulerSecuritypredicate(@Company AS nvarchar(30))
    RETURN SELECT 1 AS fn_securitypredicate_result
    WHERE (@Company = 'Mr. Meat' AND SUSER_NAME() = 'SCHOUW\Taskshed1') OR
    (@Company = 'Mr. Vegan' AND SUSER_NAME() = 'SCHOUW\TaskShed2') ;

    CREATE SECURITY POLICY TaskShedulerCompanyFilter
    ADD FILTER PREDICATE dbo.fn_TaskShedulerSecuritypredicate([Company])
    ON [dbo].[Scheduled Task]
    WITH (STATE = ON);
  • Options
    igor.chladiligor.chladil Member Posts: 28
    Thanks bertvangestel for your solution.
    It really sounds like a solution that shall work.
    I would rather prefer MS to give us some options to do that inside BC/NAV rather than hacking with NAV system tables under the hood, but still your suggestion is a viable option.
Sign In or Register to comment.