Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
stefankrauth
Active Participant

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



23 Comments