Technical Articles
Background Task Manager Template
Overview
The Cloud Application Studio does not allow asynchronous task execution. Webservice calls, Business Object updates.. everything is running in a synchronous way within an application. There is one entity, which runs in background task: Mass Data Run Objects (MDRO). My colleague Stefan Kiefer found a way to leverage MDRO functionality in a normal (non MDRO) application and kick off background tasks via ABSL script. He has built a template, which enables you to quickly leverage this functionality. The template contains an MDRO and the necessary library to schedule and execute background tasks. We call this: The Background Task Manager template.
Technical Implementation
The Background Task Manager is essentially a prebuild set of a fully developed MDRO on top of a custom business object plus libraries that can be used to schedule, execute and check the status of a scheduled task. A normal MDRO can be scheduled on an MDRO screen, which is a manual activity. This template provides libraries that allow you to do this scheduling from an ABSL script. This allows to create background tasks, set parameters and execute code right on any event when ABSL code is run.
The template contains the following entities:
Template Content
Codelist/BackgroundTaskType.codelist
The BackgroundTaskType.codelist contains a list of background tasks that can be triggered later on. If you want to use the background task manager to execute 2 independent background tasks, you can add more values here. The key is used to differenciate the tasks in Action-BackgroundTask.absl.CustomBOs/BackgroundTaskManager.bo
This custom business object is used by the MDRO. It hosts all metadata needed to execute the background task.CustomBOs/BackgroundTaskManager.bo → MDROQuery.qry
This the generated MDRO query.CustomBOs/BackgroundTaskManager.bo → Root.node → ActionBackgroundTask.absl
This script contains the code that runs in background.CustomBOs/BackgroundTaskManager.bo → Root.node → Event-BeforeSave.absl
This script handles the transient Parameter3. Only this paramenter can take unlimited text, like a binary string. Per default, this parameter saves the string supplied in an AttachmentFolder.CustomBOs/BackgroundTaskManager_*.uicomponent
These screens can be used in case you want to build a debug environement. Otherwise, these screens can be ignored.MDRun/MDR_ExecuteTask.run
This is the MDRun object. It is configured to operate on the BackgroundTaskManager.bo and takes two arguments: 1) TaskType, which is a value defined in BackgroudTaskType.codelist and 2) TaskUUID, which is a UUID that will identify the created task.MDRun/MDR_ExecuteTask_*.uicomponent
These screens can be used in case you want to build a debug environement. Otherwise, these screens can be ignored.ReuseLibrary/MDRO_Lib.library → ExecuteTaskInBackground.absl
This script can be used to execute a task, which has been scheduled before. It takes a task UUID as argument.ReuseLibrary/MDRO_Lib.library → GetTaskStatus.absl
This script can be used to retrieve the current execution status of a given task. It takes a task UUID as argument.ReuseLibrary/MDRO_Lib.library → ScheduleTaskInBackground.absl
This script can be used to setup and schedule a task in background. It takes a UUID (which you can generate), a task type (from BackgroundTaskType.codelist) and 4 further random parameters. This 4 parameters can be used by you to pass information from the application logic to the background task.
The only entities you need to change when implementing the Background Task Manager are:
BackgroundTaskType.codelist
ActionBackgroundTask.absl
Everything else should work out of the box. The template kicks off a task 3 seconds after the “ExecuteTaskInBackground” function is called. In case you want a higher delay, change “PT3S” to a higher value (example PT15S for 15 seconds) in ExecuteTaskInBackground.absl
.
Step 1: Import the template into your solution
Open the solution you would like to import the Background Task Manager. Then open the Implementation Manger (View → Implementation Manager). Click Import Template:
Select the template file, which you can download at the end of this blog.
Once the import is finished, you will find the “BackgroundTaskManager” folder in your solution.
Activate all imported entities top down: (Codelist, BO, MDRRun, Libraries)
Step 2: Define a background task
Open BackgroundTaskManager/Codelist/BackgroundTaskType.codelist. Change/add a background job. For example “001 – Terribly long running webservice call”.
Step 3: Schedule and Execute the Background Task
The following code will schedule and execute a Background Task. Let’s imagine you want to call a long running webservice call in the Ticket save. Then you would place this code in the ticket Event-BeforeSave.absl:
var TaskUUID : UUID;
TaskUUID.content = Library::UUID.Generate();
MDRO_Lib.ScheduleTaskInBackground(TaskUUID, "001",toRoot.UUID,Context.GetCurrentGlobalDateTime(),toRoot.ID.content.RemoveLeadingZeros(),"");
MDRO_Lib.ExecuteTaskInBackground(TaskUUID);
var TaskUUID : UUID;
Create a structured local variable of type UUID.
TaskUUID.content = Library::UUID.Generate();
Generate a random, unique UUID and save it in TaskUUID.content.
MDRO_Lib.ScheduleTaskInBackground(TaskUUID, TaskType,Parameter1:UUID,Paramenter2:GLOBAL_DateTime,Parameter3:XPEString,Parameter4:Text)
Schedule the Background task. This code actually creates an instance of BackgroundTaskManager.bo. The parameters are stored in this BO. You only need the first two, but it makes sense to give more parameters to it. At least one ID or UUID that identifies the BO you want to work on. The Background Task Manager executes the Action-BackgroundTask.absl and there you only have the information available supplied to this method. Parameter3 is reserved for an unlimted long string which will be saved in an attachment folder.
MDRO_Lib.ExecuteTaskInBackground(TaskUUID);
This executes the before defined Background Task. The UUID supplied here, must be the UUID that was used to schedule the Background Task.
MDRO_Lib.GetTicketStatus(TaskUUID);
You can used GetTicketStatus to read the job status of the job with the given UUID.
Step 4: Implement the Background Task
The code the background job will execute is implmented in Action-BackgroundTask.absl
.
A typical skeleton would look like this:
foreach (var RootInst in this)
{
var Parameter3String = this.AttachmentFolder.DocumentList.FileContent.GetFirst().BinaryObject.content.ToString();
switch (RootInst.TaskType)
{
case "001"
{
// long running webserive
}
case "002"
{
// send a couple of emails
}
}
}
In this ABSL, you have access too all information you have supplied to MDRO_Lib.ScheduleTaskInBackground(). The switch statement differentiates between the TaskTypes given, so only the Task defined in BackgroundTask.codelist and given into ScheduleTaskInBackground() is executed. Feel free to implement whatever you want in here. If you supplied the calling object UUID, you can retrieve the calling object and read more data from it.
Pitfalls
- Think about object locking. If you schedule a background task on a object save and write data back to the object, think about the Quick Create Save + Open case. There a save is executed and the object is opened (and locked) immediately. In this case, the background task would fail. Based on the retention time defined on the MDRO (1day per default) a second run will be executed. This may lead to unwanted effects. For example if you send emails or call synchronous webservices, but then the save doesn’t work, the same calls/mails may be sent again a day later.
- Think about multiple execution of events. Sometimes script files are called multiple times.
- If you create multiple background jobs, make sure they do not lock the same objects at the same time.
Use case: Detach Workflow Rules from a standard object to enhance save performance
This is a draft and may be outsourced into a separate blog entry with more details
Workflow rules can be used to do several things on business object state changes. One big downside of workflow rules is, that they are slow. If you have defined many workflow rules, this can add easily add up to 5-10 seconds just to evaluate the rules (not counting the actual execution). You can use the Background Manager to decouple the rules from the main (standard) business object.
The standard process executes the save and the WF rules sequentially:
With the background task manager it is possible to decouple the WF process and make it run in background task on a proxy object. The time used in background does not affect the user experience:
1. Determine scope
Define all fields you need for the WF rule determination. These are all fields you want to use in the criteria selection when creating a workflow rule.
2. Create a custom proxy business object
Once the fields a defined, create a business object, that contains elements for all these fields. Enable notification rules for this object (right click → enable notification rules). Once a BO is enabled for notification rules, you can also build workflow rules on it. The notification rules wizard needs a UUID field as reciepient. Make sure you have such a field in the BO model. It can be a dummy field.
4. Create an Update Background Task Manager Job
Create a background task, that reads the standard object and copies all the selection criteria field information into the custom proxy business object. Trigger the Background Task at the end of the BeforeSave event. Implement the code to copy the fields over in the Action-BackgroundTask in the BackgroundTaskManager.
5. Create workflow rules on the custom proxy business object
You can now create workflow rules on the custom proxy business object. These rules can send emails and do everything that does not write back to the standard business object. Keep field update WF rules on the standard business object. You have now successfully moved your workflow rules into background task.
Download link removed. Reason: 404 not found
Hey Stefan,
Thanks for sharing the information. 🙂
Regards,
Chandan Bankar
Very useful, thanks for sharing!
Jan
Amazing content and experiment Stefan 🙂
Thanks for sharing.
Hello Stefan,
Thanks a lot, for sharing.
i have a question:
How can I set programmatically the MDR_Task as a recurring task?
Notice:
In GetTaskStatus, you forgot to pass a return parameter
I think you wanted that?:
Best regard,
Said
Hello Said,
this is not what you want to do. In this case, the MDRO is "used" to be triggered automatically from an ABSL event.
If you want to create a normal MDRO that you want to schedule, you're probably in better shape by creating a MDRO from scratch with the steps described in the documentation.
But to answer your question, you can schedule the MDRO from the frontend. But you need to make the screens visible by creating WorkcenterViews and assign them to a Workcenter and to your user.
Best Regards,
Stefan
Hello Stefan,
thank you very much.
Some important questions:
Best Regards
Said
Hi Moshref,
there is no limitation of background tasks. You can get the status, but you also have to set it yourself in the Action-BackgroundTask. Otherwise you will always get "not startet".
Best Regards,
Stefan
Awesome !! Thank you so much Stefan Hagen for sharing this and many thanks to Stefan Kiefer for creating this 🙂 .
Hello Stefan,
Many thanks for your great sharing, it's very useful to build a central task manager with high-custom-demand purpose.
Just one more question, is there any way to active created task instances via ABSL code? Noticed that reuse library MDRO can only create and schedule task instances, but it's mandatory to active instances before running them. If not, then Task Manager you mentioned can only manage active task instances, right?
Thanks in advance.
Br, Andy
Hi Andy,
Once a task is scheduled, it's automatically activated. There is no manual activation necessary.
Best Regards,
Stefan
Hello Stefan,
You are very generous to share your experience,but I cant't download the template file,can you send it to my mail box:baoxiang.lv@infosysconsulting.com
Thans in advance and looking forward to your reply!
Hello,
The link should work again.
Best Regards,
Stefan
Hello Stefan,
Thanks very much ,you are so kindly
Best Regards,
Baoxiang
Hello Stefan,
This seems to be a very, very useful tool, appreciate your engagement.
Unfortunately, the link doesn't work. Would you please be so kind to share it again?
Thanks,
Pablo
Hi Pablo,
The link should work again.
Best Regards,
Stefan
Hi Stefan,
Thank you!
Unfortunately, I had to realize that the Template is built for C4C and cannot be uploaded to a ByD tenant.
Is there a way to convert the Solution Template to make it work on a ByD-tenant or do I have to re-engineer it completely?
Thanks,
Pablo
Hi Pablo,
the template only works on C4C. The underlying functions are not present in BYD.
Best Regards,
Stefan
Hi Stefan,
Thanks for this very useful template.
I get the following error message when trying to upload the template to a 1708 system: "Release SAP_LEAP 611 of solution is not compatible with system".
Any chance you could update the template to work with 1708 ?
Best Regards.
Rodrigue
Hi Rodrigue,
I've updated the link. The updated Version is valid for 1708, 1711 and 1802.
Best Regards,
Stefan
Thanks Stefan, everything works perfectly.
Best Regards.
Rodrigue
Hi Stefan,
Can you please update the link again?
Hi Stefan,
can you please update the link again an make it compatible with 1811?
Thanks & regards,
Fabian
Hi Stefan,
Could you please update the link?
Thank you, regards.
Kursat