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

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:

Template Import

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.

Import Done

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:

WF standard

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:

WF proxy

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 BACKGROUND TASK MANAGER TEMPLATE

To report this post you need to login first.

11 Comments

You must be Logged on to comment or reply to a post.

  1. Said Moshref

    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?:

    var result : DataType::ProcessingStatusCode;
    
    
    
    var MDROID : XPEString;
    
    
    
    MDROID = TaskUUID.content.ToString();
    
    
    
    result = MDRO.GetJobStatus("MDR_ExecuteTask", "", MDROID);
    
    
    
    return result;

    Best regard,

    Said

    (0) 
    1. Stefan Hagen Post author

      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

      (0) 
  2. Said Moshref

    Hello Stefan,

     

    thank you very much.

    Some important questions:

    •  Is there a limitation of background jobs?
    • I can’t get the status of the running job, it is maybe not working?

     

     

    Best Regards

     

    Said

    (0) 
    1. Stefan Hagen Post author

      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

      (0) 
  3. Andy He

    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

    (0) 
  4. baoxiang lv

    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!

    (0) 
  5. Pablo Menth

    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

     

    (0) 

Leave a Reply