Data Streaming

Sometimes you need to present the results from a robot execution in real-time, as the robot is executing. In these cases you want the API to return the extracted values immediately instead of waiting for the robot to finish its execution and access the RqlResult.

The API offers the possibility to receive a callback every time the API receives a value that was returned by the Robot. This is done through the IRobotResponseHandler interface


using System;
using Com.KapowTech.RoboSuite.Api;
using Com.KapowTech.RoboSuite.Api.Repository.Construct;
using Com.KapowTech.RoboSuite.Api.Construct;
using System.IO;
using Com.KapowTech.RoboSuite.Api.Engine.Hotstandby;

namespace Examples
{

    public class DataStreaming {

        public static void Main(String[] args)  {

            var server = new RoboServer("localhost", 50000);
            var cluster = new Cluster("MyCluster", new RoboServer[] { server }, false);
            Request.RegisterCluster(cluster);

            var request = new Request("Library:/Tutorials/NewsMagazine.robot");
            IRobotResponseHandler handler = new SampleResponseHandler();
            request.Execute("MyCluster", handler);
        }

    }


    public class SampleResponseHandler : AbstractFailFastRobotResponseHandler
    {
        override public void HandleReturnedValue(RobotOutputObjectResponse response, IStoppable stoppable)
        {
            var title = response.OutputObject["title"];
            var preview = response.OutputObject["preview"];
            Console.WriteLine(title + ", " + preview);
        }
    }
}
                            

Response streaming usingAbstractFailFastRobotResponseHandler


The above example uses the second execute method of the Request, which expects a RobotResponseHandler in addition to the name of the cluster to execute the robot on. In this example we create a IRobotResponseHandler by extending AbstractFailFastRobotResponseHandler, which provides default error handling, so we only need to handle the values returned by the robot.

The handleReturnedValue method is called whenever the API receives a returned value from RoboServer. The AbstractFailFastRobotResponseHandler used in this example, will throw exceptions in the same way as the non-streaming execute method. This means that an exception will be thrown in response to any API exceptions generated by the robot.

The IRobotResponseHandler has several methods which can be grouped into 3 categories.

Robot life cycle events

Methods which are called when the robot's execution state change on RoboServer, such as when it starts and finishes its execution.

Robot data events

Methods which are called when the robot returns data or errors to the API.

Additional error handling
Methods which are called either due to an error inside RoboServer or in the API.

Method name Description
void RequestSent(RoboServer roboServer, ExecuteRequest request) Called when the RequestExecutor has found the server which will execute the request.
void RequestAccepted(String executionId) Called when the found RoboServer has accepted the request, and put it into it queue.
void RobotStarted(IStoppable stoppable) Called when the RoboServer begins to execute the robot. This usually occurs immediately after the robot has been queued, unless the RoboServer is under heavy load, or used by multiple API clients.
void RobotDone(RobotDoneEvent reason) Called when the robot is done executing on RoboServer. The RobotDoneEvent is used to specify if the execution terminated normally, due to an error, or if it was stopped.

IRobotResponseHandler - robot life cycle events


Method name Description
void HandleReturnedValue(RobotOutputObjectResponse response, IStoppable stoppable) Called when the robot has executed a Return Value action, and the value has been returned via the socket to the API.
void HandleRobotError(RobotErrorResponse response, IStoppable stoppable) Called when the robot raises an API exception. Under normal circumstances the robot will stop executing after the first API exception. This behavior can be overridden by using Request.StopRobotOnApiException = false, in which case this method will be called multiple times. This is useful if you want a data streaming robot to continue to execute regardless of any generated errors.
void HandleWriteLog(RobotMessageResponse response, IStoppable stoppable) Called if the robot executes the Write Log action. This is useful if you wish to provide additional logging info from within a robot.

IRobotResponseHandler - robot data events


Method name Description
void HandleServerError(ServerErrorResponse response, IStoppable stoppable)

Called if RoboServer generates an error, for instance if the server too busy to process any requests, or if an error occurs inside RoboServer which prevents it from starting the robot.

void handleError(RQLException e, IStoppable stoppable) Called if an error occurs inside the API. Most commonly if the client looses the connection to RoboServer.

IRobotResponseHandler - additional error handling


Many of the methods will include a IStoppable object, this object can be used to stop for instance in response to a specific error or value returned.

Some of these methods allow you to throw an RQLException, if you do this you should be aware of the consequences. The thread that calls the handler is the thread that calls Request.Execute(), this means that any exceptions thrown will bubble up the call stack and out the execute method. If you throw an exception in response to handleReturnedValue, handleRobotError or handleWriteLog it is your responsibility to invoke Stoppable.stop(), or the robot may continue to execute even though the call to Request.Execute() has completed.

Data streaming is most often used in one of the following use cases.

using System;
using System.Collections;
using System.Collections.Generic;
using Com.KapowTech.RoboSuite.Api;
using Com.KapowTech.RoboSuite.Api.Repository.Construct;
using Com.KapowTech.RoboSuite.Api.Construct;
using System.IO;
using Com.KapowTech.RoboSuite.Api.Engine.Hotstandby.Interfaces;

namespace Examples
{
    public class DataStreaming
    {

        public static void Main(String[] args)
        {

            var server = new RoboServer("localhost", 50000);
            var cluster = new Cluster("MyCluster", new RoboServer[] { server }, false);
            Request.RegisterCluster(cluster);

            var request = new Request("Library:/Tutorials/NewsMagazine.robot");
            request.StopRobotOnApiException = false;  // IMPORTANT!!

            ErrorCollectingRobotResponseHandler handler = new ErrorCollectingRobotResponseHandler();
            request.Execute("MyCluster", handler); // blocks until robot is done, or handler throws an exception

            Console.WriteLine("Extracted values:");
                foreach (RobotOutputObjectResponse response in handler.GetOutput())
            {
                var title = response.OutputObject["title"];
                var preview = response.OutputObject["preview"];
                Console.WriteLine(title + ", " + preview);
            }

            Console.WriteLine("Errors:");
            foreach (RobotErrorResponse error in handler.GetErrors())
            {
                Console.WriteLine(error.ErrorLocationCode + ", " + error.ErrorMessage);
            }
        }
    }


    public class ErrorCollectingRobotResponseHandler : AbstractFailFastRobotResponseHandler {

        private IList<RobotErrorResponse> _errors = new List<RobotErrorResponse>();
        private IList<RobotOutputObjectResponse> _output = new List<RobotOutputObjectResponse>();

        override public void HandleReturnedValue(RobotOutputObjectResponse response, IStoppable stoppable)  {
            _output.Add(response);
        }


        override public void HandleRobotError(RobotErrorResponse response, IStoppable stoppable) {
            // do not call super as this will stop the robot
            _errors.Add(response);
        }

        public IList<RobotErrorResponse> GetErrors() {
            return _errors;
        }

        public IList<RobotOutputObjectResponse> GetOutput() {
            return _output;
        }
    }
}
                            

Response and error collecting using AbstractFailFastRobotResponseHandler


The example above shows how to use a IRobotResponseHandler that collects returned values and errors. This type of handler is useful if the robot should continue to execute even when error are encountered, which can be useful if the website is unstable and occasionally times out. Notice that only robot errors (API exceptions) are collected by the handler, if the connection to RoboServer is lost Request.Execute() will still throw an RQLException (and the robot will be stopped by RoboServer).

For more details check the IRobotResponseHandler chm documentation in the /docs folder .