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

Hello,

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 ...

Thanks,
Igor

Answers

  • RoelofRoelof Posts: 348Member
    I have the same question as Igor.
    Any ideas anyone?
    Roelof de Jong
    http://www.esopro.com
  • HannesHolstHannesHolst Posts: 119Member
    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.

    Cheers,
  • OldNavDogOldNavDog Posts: 87Member
    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.
  • igor.chladiligor.chladil Posts: 28Member
    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.

    Regards,
    Igor
  • HannesHolstHannesHolst Posts: 119Member
    Hi,

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

    @igor.chladil
    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
    ServerInstance.GET(SERVICEINSTANCEID);
    IF ServerInstance."Service Name" <> JobQueueEntry."Server Instance to be executed on" THEN
      EXIT;
    
    // check for current session
    IF SESSIONID <> JobQueueEntry."Session to be executed in" THEN
      EXIT;
    
    ExecuteFunction(); // call Codeunit or Report as configured in Job Queue Entry here
    

    Additionally you could do something like this:
    // get current server instance
    ServerInstance.GET(SERVICEINSTANCEID);
    IF ServerInstance."Service Name" <> JobQueueEntry."Service to be executed on" THEN
      EXIT;
    
    // 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).
  • JuhlJuhl Posts: 636Member
    The workaround only solves job queue entries. Not Scheduled Task.
    Follow me on my blog juhl.blog
  • HannesHolstHannesHolst Posts: 119Member
    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.
  • vremeni4vremeni4 Posts: 304Member
    Hi

    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.

    Thanks.
  • JuhlJuhl Posts: 636Member
    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
  • RydenRyden Posts: 24Member
    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.
    --
    www.nabsolutions.se
  • BlackTigerBlackTiger Posts: 1,211Member
    edited 2018-11-29
    Just use "old sKool" NAS and some custom code to run some specific tasks.

    PS: built-in task scheduler executes tasks in parallel already so it can help if you don't care about load balancing issues.
    "You can’t just ask customers what they want and then try to give that to them.
    By the time you get it built, they’ll want something new.” Steve Jobs
  • RydenRyden Posts: 24Member
    We need to split this on two different servers, running both jobs on one server chokes it to death.
    --
    www.nabsolutions.se
  • BlackTigerBlackTiger Posts: 1,211Member
    "You can’t just ask customers what they want and then try to give that to them.
    By the time you get it built, they’ll want something new.” Steve Jobs
  • BlackTigerBlackTiger Posts: 1,211Member
    Ryden wrote: »
    We need to split this on two different servers, running both jobs on one server chokes it to death.

    Just use several NASes and custom "job queue" to execute your tasks. This is the best solution.
    "You can’t just ask customers what they want and then try to give that to them.
    By the time you get it built, they’ll want something new.” Steve Jobs
  • bertvangestelbertvangestel Posts: 1Member
    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.

    https://docs.microsoft.com/en-us/sql/relational-databases/security/row-level-security?view=sql-server-2017


    CREATE FUNCTION fn_TaskShedulerSecuritypredicate(@Company AS nvarchar(30))
    RETURNS TABLE
    WITH SCHEMABINDING
    AS
    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);
  • igor.chladiligor.chladil Posts: 28Member
    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.