I had someone reach out to me about the ‘right’ way to handle batch jobs when disabling or deleting a user from D365FO. Let’s look at the options you have to avoid any issues.
Why This is an Issue
Batch jobs within D365FO allow for a way to execute a set of instructions that can be scheduled to run on a periodic basis. These are used extensively to perform business calculations and because they can be set to execute at a certain time, can be performed outside of normal business hours to minimize impact to the system.
Each batch job runs under the context of a user within the system. If that user is disabled, the batch jobs tied to that user will not be able to execute and will fail. What’s more, if a user is deleted any batch job tied to that user is also deleted!
These issues are well known as there have been multiple posts about this topic:
Does batch job stop working if you disable the user account which set it up?
Life’s a batch… (from fellow Microsoft MVP Andre Arnaud de Calavon)
The two scenarios above can obviously lead to unintended consequences within the system. So how do we address this?
Possible Solutions
I have two separate ways that I have used with customers to address this issue:
– Use table events to capture when a change occurs to the UserInfo table (either disabling a user or deleting a user) and assign all batch jobs for that user to an ‘admin’ type user
– Build a custom form to allow you to reassign batch jobs to any user you would like, using this you can be proactive about reassigning batch jobs before you actually disable or delete a user
The first scenario is more static as you are always assigning the batch jobs to a single user but it is easier to build. The second solution is more flexible but adds a lot of complexity for the solution.
The custom form option will probably be dependent on the customer, so let’s look at how we could use the first option to come up with a solution.
Table Event Solution
Using table events we can listen for events that update or delete from the UserInfo table, which is the table that stores master data information about users. Specifically we need to handle two different scenarios where the user impacted has batch jobs tied to them:
- An update to a user that changes the user from ‘enabled’ to ‘disabled’
- A delete to a user
To determine if a user change would impact a batch job we first have to look to see where batch jobs are tied to a user, on the BatchJob table we can see there is an ExecutingBy field. This is the user the batch job will execute as and the field we need to change based on events above.
This field ties to the ‘Run By’ field on the Batch Jobs form (which can be found at System Administration -> Inquiries -> Batch Job):
So the idea would be to listen for changes to a user that meet one of the criteria above and if there is such a change check to see if that user is set to ‘run’ any batch jobs and if so to change the ‘run by’ to another user.
To do this, I added the following code to our test environment:
To break down the code a bit:
– The first section is listening for update events happening to the UserInfo table and it is explicitly looking for changes to the ‘enable’ field. If the old and new values for the ‘enable’ field are different and if the new value is set to false then look for batch jobs where the ‘ExecutingBy’ user is this user and update to an admin user.
– The second section is listening for delete events happening to the UserInfo table and performing the same check for batch jobs where the ‘ExecutingBy’ user is set to the user being deleted and updating the record to an Admin user. One thing to note here is that both events are listening to the Updating/Deleting event, this is to hook into the event before it is completed which in the case of a deletion allows us to modify the batch job record before it would be deleted because the user is deleted.
You can find a text version of the code above here.
Testing Solution
Let’s first go in and test disabling a user with batch jobs tied to them. We are going to use this CHARLIE user as our test, he has a couple batch jobs where he is the ‘Run by’ user:
When we go to disable the user we get this warning:
Looking at the code, this is because within a validateWrite() method of the user UserInfo table that any batch job created by or executing by the user will generate this warning:
In our case though, the ‘Run by’ user is already updated to our Admin user:
So now that we have tested updating a user, we can now switch to testing deleting a user, to test this we will use the CHRIS user which has the following batch job associated to his user:
So now if we go ahead and delete this user:
We can see this batch job still exists (!) and has been moved to ‘run by’ our Admin user:
Conclusion
If you wanted to take this a step further you could take the code above and utilize it when creating a custom form if you wanted. One thing I will say is that to the point Andre made in his blog post from above all of this can be avoided if the batch job is set up to use a service account, which also would be my recommendation but in case that is not possible the above solution will help to ensure your batch jobs continue to run smoothly.
Alex,
This is a great write-up! Thank you for making this available to the F&O community.
Never run a business critical batch job under a normal user account. Instead, create a separate batch user and create business critical batch job by using this batch user. If you follow this golden rule, then there is no need for the scripts above.
Jeroen,
I agree and mention this in the blog post, the best practice here is to always have service accounts executing your batch jobs so you never run into this situation. But in practice I have ran into this issue with customers more often than I would like to admit so I offered this as a solution for those instances.
I don’t think the deleting part works as expected. Just by updating the ‘Run by’ field, the batch jobs still get deleted if the user is deleted. Because in the delete method of ‘SysUserInfo’ table it deletes all the batch jobs created by that user. Since we cannot update the created by field the batch jobs are deleted. Am I missing something here?
Haris,
You are correct if the batch job was created by the user that is being deleted there is nothing we can do to stop the associated batch jobs from also being deleted as we cannot update the ‘CreatedBy’ field. You will notice in my example that the batch job was created by the ‘Admin’ user and being executed by the ‘CHRIS’ user, in scenarios like this the code provided will work as expected.
If we change the username and email to the user does it affect existing scheduled batches
Raghu,
Changing the user properties should not impact batch jobs.
Hi Alex, First of all thank you for writing such a wonderful and organized post.
Two (may be) related questions:
1) What are the “Critical” & “Private job” check boxes on the batch job screen?
2) If you delete a user, what happens to the transactions posted by that user? Like General Journals, sales orders, purchase orders?
Shakir,
Here is a link on ‘critical’ batch jobs – https://learn.microsoft.com/en-us/dynamics365/fin-ops-core/fin-ops/organization-administration/workflow-batch-job-critical
Here is a link on the ‘private’ batch jobs – https://learn.microsoft.com/en-us/dynamicsax-2012/appuser-itpro/run-client-and-private-batch-tasks
When a user is deleted and they have transactions in the system, the audit records are left as is but there is no user to tie those transactions back to anymore. This is one of the many reasons that a majority of companies do not ‘delete’ a user and instead just ‘disabled’ a user when the leave the organization.