Skip to Content
Technical Articles

Handling errors and timeouts in a scenario

1. Introduction

My name is Samir Hamichi, I’m part of the SAP Intelligent Robotic Process Automation Customer Adoption Team.

In a series of blog posts, I want to give some best practices from the development perspective. I will focus on the Low Code/No code approach.

This blog post will cover errors and timeouts handling. First, I’ll explain the content of the default generated handlers: sc.onTimeout() and sc.onError(). In addition to the data you access via their parameters, I’ll give you some insights about useful global data you can leverage in these callbacks like information related to the user or computer running the project, information about the project like version, title, etc…

From the workflow designer, I’ll show the Error and Timeout activities and how to use them connecting additional logging activities before ending the scenario. I added some useful function that logs errors into Business Activity Monitoring system, CSV file or database.

Last, I show how to handle errors and timeouts within a given step. This gives you the possibility to do custom handling.

This Blog post is related to a webinar: How to manage errors during bot execution.

2. Context and steps

I’ll show you a very simple scenario with a custom step to explain the generated code and then add some custom code that allow me to illustrate handling of some errors and timeouts.

 

2.1. Workflow creation

I create a project named ErrorTimeoutMgt and create a workflow called FundsProcessing with one custom step. I save and build the project to generate the scenario script.

 

2.2. Scenario declaration

From the generated code, we extract the declaration of the scenario as a bloc:

// ----------------------------------------------------------------
//   Scenario: FundsProcessing
// ----------------------------------------------------------------
GLOBAL.scenario({ FundsProcessing: function(ev, sc) {
	var rootData = sc.data;

	sc.setMode(e.scenario.mode.clearIfRunning);
	sc.setScenarioTimeout(600000); // Default timeout for global scenario.
	sc.onError(function(sc, st, ex) { sc.endScenario(); }); // Default error handler.
	sc.onTimeout(30000, function(sc, st) { sc.endScenario(); }); // Default timeout handler for each step.
	sc.step(GLOBAL.steps.Custom);
}}, ctx.dataManagers.rootData).setId('5c004f3a-7b59-45c3-972e-2cf7a7e1f207') ;

 

Among the different components of the scenario, we distinguish the following:

  • A mode as starting condition according to business rules: here in our example, clear if there is a running instance of the scenario.
sc.setMode(e.scenario.mode.clearIfRunning);

 

You can access the different modes with code completion.

  • A timeout for the whole scenario: default timeout for the whole scenario in milliseconds.
sc.setScenarioTimeout(600000); // Default timeout for global scenario.
  • A state machine of the steps used in the scenario: this scenario is very simple with only one step.
sc.step(GLOBAL.steps.Custom);

 

Now, let’s focus on the Error and Timeout callbacks. In the snippet, we extract the code of the sc.onError & sc.onTimeout callbacks and add some indentation, we notice that it contains only an end scenario instruction: sc.endScenario.

  • A callback for errors/exceptions handling: default error handler raised whenever an exception occurs during execution of the scenario.
sc.onError(function(sc, st, ex) { 

    sc.endScenario(); 

}); // Default error handler.
  • A callback for timeout handling with timeout value: each step has a timeout, usually set to 30000 milliseconds. If the execution of the step exceeds this defined timeout, the callback is raised.
sc.onTimeout(30000, function(sc, st) { 

    sc.endScenario(); 

}); // Default timeout handler 

 

Indeed, whenever an error occurs during runtime, as default behavior, the scenario ends without additional.

Notice that each callback has its own input parameters. they allow us to add some additional code like logging/cleaning data, resetting of processes/application states, etc.

Both of the callbacks have access to the current running scenario (sc) and the current running step (st).These objects have many parameters and functions that we can use inside the callbacks.

  • the current running scenario (sc)

  • the current running step (st)

The only difference between the two callbacks is the exception parameter (ex) that is specific for the sc.onError callback. It contains the details of the raised exception:

  • the current raised exception (ex)

Inside the scope of the callbacks, you can have access to additional information. One of the useful modules is the ctx.options module. It contains the project management options (Documentation).

Here is my selection of those I usually use:

  • the module ctx.options:
    • Computer name: ctx.options.computerName
    • User login: ctx.options.userName
    • Project name: ctx.options.projectName
    • Project client: ctx.options.projectClient
    • Project comment: ctx.options.projectComment
    • Project title: ctx.options.projectLabel
    • Project uid: ctx.options.projectUid
    • Project version: ctx.options.projectVersion
    • Trace:
      • Auto-recording: ctx.options.trace.autoRecording
    • Different path variables:
      • Folder containing Desktop Agent binaries: ctx.options.path.exec
      • Folder containing project files: ctx.options.path.local
      • Folder log and work files: ctx.options.path.log
      • Folder containing server project files: ctx.options.path.server
      • Folder containing resources files: ctx.options.path.resources

We will comeback to use them later in the implementation of 3 functions as additional log configurations .

For now, let’s go back to the workflow designer and show you two very important activities related to our callbacks. Error activity & Timeout activity.

 

2.3. Scenario Error and Timeout activities

Among the scenario activities we distinguish Error and Timeout activities illustrated below:

 

When used in the workflow, the Error activity (resp. Timeout  activity) override the onError callback (resp. onTimeout callback) of the scenario.

 

The configuration below shows how we can use the Error activity. Respectively, the same could be done for the Timeout activity.

  • First, drag and drop the Error activity into the workflow chart
  • Second, add a log activity with the following properties:
    • Message: “An exception has been raised, error:”+ex.name +” – message:’+ex.message
    • Level: Error
    • Note that here we can:
      • add others information concatenated.
      • call a global function in the Message property.
  • Third, add an explicit End scenario activity

 

Below, the corresponding generated code of the previous configuration:

// ----------------------------------------------------------------
//   Scenario: FundsProcessing
// ----------------------------------------------------------------
GLOBAL.scenario({ FundsProcessing: function(ev, sc) {
	var rootData = sc.data;

	sc.setMode(e.scenario.mode.clearIfRunning);
	sc.setScenarioTimeout(600000); // Default timeout for global scenario.
	// Error management
	sc.onError(function(sc, st, ex) {
		ctx.workflow('FundsProcessing', 'ee228015-5aa8-4390-8494-f5ef1178a860') ;
		// Write log
		ctx.log('An exception has been raised!'+ex.message, e.logIconType.Info);
		ctx.workflow('FundsProcessing', '2afd7a3b-3673-4639-93a5-3cf601a099a1') ;
		// End scenario
		sc.endScenario();
		return;
	}); // Error handler.
	sc.onTimeout(30000000, function(sc, st) { sc.endScenario(); }); // Default timeout handler for each step.
	sc.step(GLOBAL.steps.Custom);
}}, ctx.dataManagers.rootData).setId('5c004f3a-7b59-45c3-972e-2cf7a7e1f207') ;

 

In the second step (Log activity), we can think of other activities like

  • adding logs in the Business Activity Monitoring system
  • writing in a file: excel, csv, json, text, etc.
  • calling an external global function that writes into a database

 

2.4. Additional log configurations

In the following examples, I’ve created in a script Settings.js of my project. It contains the 3 following functions:

  • logBAMfailure(sc, st)
  • logCSVfailure(sc, st)
  • logDBfailure(sc, st)

I use these external functions in my log activities to save my errors in different locations. They are generic function that can be reused in several scenarios and projects.

 

2.4.1. Configuration A: Business Activity Monitoring (BAM)

 

The Message property is a call for a function logBAMfailure(sc, st)

	sc.onError(function(sc, st, ex) {
		// Writing logs in Business Activity Monitoring 
		ctx.log(logBAMfailure(sc, st), e.logIconType.Error);
		ctx.workflow('FundsProcessing', '2afd7a3b-3673-4639-93a5-3cf601a099a1') ;
		// End scenario
		sc.endScenario();
		return;
	}); // Error handler.

 

The implementation of logBAMfailure(sc, st) function:

// ----------------------------------------------------------------
//   Logs in BAM
// ----------------------------------------------------------------
var logBAMfailure = function(sc, st){
	try {

		ctx.monitor.notifyError("Alert1", sc.code, "Exception raised", "Scenario failed in step"+st.name+ " - sc.label:"+sc.label);

	} catch (error) {
		ctx.log('BAM insertion failed: '+ error.description );
	}
}

If you want to get more on BAM activities:

 

2.4.2. Configuration B: Write in CSV

 

The Message property is a call for a function logCSVfailure(sc, st)

	sc.onError(function(sc, st, ex) {
		// Writing logs in CSV
		ctx.log(logCSVfailure(sc, st), e.logIconType.Error);
		ctx.workflow('FundsProcessing', '2afd7a3b-3673-4639-93a5-3cf601a099a1') ;
		// End scenario
		sc.endScenario();
		return;
	}); // Error handler.

 

The implementation of logCSVfailure(sc, st) function:

// ----------------------------------------------------------------
//   Logs in CSV
// ----------------------------------------------------------------
var logCSVfailure = function(sc, st){
	/*
		Strings for CSV entry:
		- Timestamp
		- Computer name
		- Username
		- Project name
		- Project client
		- Project comment
		- Project title
		- Project Uid
		- Project version
		- Scenario name
		- Step name
		- Scenario code 
		- Scenario label
	*/
	try{
		var entry = ctx.getTimestamp()+","+ ctx.options.computerName+","+ctx.options.userName+","+ctx.options.projectName+","+ctx.options.projectClient+","+ctx.options.projectComment+","+ctx.options.projectLabel+","+ctx.options.projectUid+","+ ctx.options.projectVersion+","+ sc.name+","+ st.name+","+ sc.code+","+ sc.label+"\r\n";
		ctx.writeFile("c:\\temp\\ErrorsLogs_Comma_separator.csv", entry,true);
	} catch (error) {
		ctx.log('CSV log failed: '+ error.description );
  }
	
}

 

 

2.4.3. Configuration C: Write in Database

 

The Message property is a call for a function logDBfailure(sc, st)

	sc.onError(function(sc, st, ex) {
		// Writing logs in Database 
		ctx.log(logDBfailure(sc, st), e.logIconType.Error);
		ctx.workflow('FundsProcessing', '2afd7a3b-3673-4639-93a5-3cf601a099a1') ;
		// End scenario
		sc.endScenario();
		return;
	}); // Error handler.

 

The implementation of logDBfailure(sc, st) function:

// ----------------------------------------------------------------
//   Logs in Database
// ----------------------------------------------------------------
var logDBfailure = function(sc, st){
	// Database connection
	var string_connection = "Provider=SQLOLEDB;Server=yourServername\\SQLEXPRESS;Database=ErrorsMgtDB;UID=yourUser;PWD=yourPassword;";
	var oConnection;
	var rs;
	
  try {
		oConnection = new ActiveXObject("ADODB.Connection");
		rs = new ActiveXObject('ADODB.Recordset');
		oConnection.Open(string_connection);
		ctx.log("Connecting to database...", e.logIconType.Event);
  } catch (error) {
		ctx.log('Connection failed: '+ error.description );
  }
	
	/* 
	select the information you need for the database and construct your SQL insert statement skipping the cote /'/ charachter if any (Done for sc.label in this case)

	I use the following fields:
		- Timestamp
		- Computer name
		- Username
		- Project name
		- Project client
		- Project comment
		- Project title
		- Project Uid
		- Project version
		- Scenario name
		- Step name
		- Scenario failure code 
		- Scenario failure label
	*/
	
	
	var insert_request = "INSERT INTO [ErrorsMgtDB].[dbo].[ErrorsTable] ([UID],[computerName],[userName],[projectName],[projectClient],[projectComment],[projectLabel],[projectUid],[projectVersion],[scenarioName],[stepName],[failureCode],[failureLabel]) 	VALUES ('"+ctx.getTimestamp()+"','"+ ctx.options.computerName+"','"+ctx.options.userName+"','"+ctx.options.projectName+"','"+ctx.options.projectClient+"','"+ctx.options.projectComment+"','"+ctx.options.projectLabel+"','"+ctx.options.projectUid+"','"+ ctx.options.projectVersion+"','"+ sc.name+"','"+ st.name+"','"+ sc.code+"','"+ sc.label.replace(/'/g," " )+"')";

	try {
		// Insert querry
		ctx.log("Insert logs to database...", e.logIconType.Event);
		rs = new ActiveXObject('ADODB.Recordset');
		rs.Open(insert_request, oConnection);
		ctx.log("Data logged with success!", e.logIconType.Event);
	} catch (error) {
		ctx.log('Insertion failed: '+ error.description );
  }
}

 

2.5. Handling error and timeout within a step

Right now, I have shown how to handle errors at the level of the scenario (respectively, the same applies to the timeout callback). Now, what if we want to handle the error and timeout within the step?

We have to customize the implementation of the step to add an st.onError to handle errors. Whenever a step is executed, the scenario starts a timer that has a timeout value from the default definition. If you want to customize the timeout for the step, you define an st.onTimeout callback with a custom timeout value. in the code below, it’s set to 60 seconds instead of the default which is set to 30 seconds.

// ----------------------------------------------------------------
//   Step: Custom
// ----------------------------------------------------------------
GLOBAL.step({ Custom: function(ev, sc, st) {
	var rootData = sc.data;
	ctx.workflow('FundsProcessing', 'c4d5018b-67cc-47b5-a135-c9a62df79773') ;
	// Custom

	st.onError( function(sc, st, ex) { 
		// My custom code if error raised in this step
		sc.endScenario();
		
	});
	st.onTimeout( 60000, function(sc, st) { 
		// My custom code if step timeout reached in this step
		sc.endScenario();
		
	});
	
	//Step code here

	sc.endStep(); // end Scenario
	return;
}});

 

3. Conclusion

In this blog post, I presented how to handle errors and timeouts of a certain scenario. I explained the code of the default callbacks generated in the scenario. I gave some insight about the accessible data that could be interesting and useful for your logs and Business Activity Monitoring.

I presented the Error and Timeout activities that you can use in the workflow designer to override the default handlers and connect additional activities before ending the scenario.

I added some useful functions that log errors in different ways: Business Activity Monitoring system, CSV file and SQL database. These functions can be taken and customized to your projects.

Last I shown how to handle errors and timeouts within a given step. This gives you the possibility to do custom handling for each step.

As a last reminder, this Blog post is related to a webinar: How to manage errors during bot execution.

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