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:
- Background printing - it was sufficient to configure printers only on one machine and pass the printing jobs via that machine
- 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.
- 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:
- Fire from Scheduled Task that task on a specific service using Web Services. But then the impersonation would not work ...
- 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
Any ideas anyone?
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,
Now if someone would only tell me how you DEBUG a Task Scheduler Task...
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
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:
Additionally you could do something like this:
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).
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.
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!
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
www.nabsolutions.se
https://community.dynamics.com/nav/b/navrashedamini/archive/2009/11/14/replacing-nas-with-sql-jobs-and-nav-web-service
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);
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.