Working with the data sent back from a task is an important element of any application.

In this section the following is explained:

Task Status

The task status describes whether the task completed successfully or encountered errors. If a task completed without throwing an uncaught exception, its status will be COMPLETED. For details on what each status code means take a look at the TaskStatus reference.

Java  Copy imageCopy
if (job.getTasks().get(0).getTaskStatus() == TaskStatus.COMPLETED) {
    // Task executed successfully.
    // Process results.
} else {
    // There was an issue in the task.
    // Perform error handling.
}

Result Property

The Result property is the main mechanism for passing data back after a task completes. Call the setResult() method and pass in the result object. For example:

Java  Copy imageCopy
public static class YourTask extends Task {
    @Override
    public void execute() {
        this.setResult("This is the result from the task.");
    }
}

Task results can also be user defined. The only requirement for the result object is that it must be serialized by the Java binary serializer. This is an example of a user defined result object:

Java  Copy imageCopy
public static class SimpleTask extends Task {
    @Override
    public void execute() {
        try {
            this.setResult(new MyTaskResult(InetAddress.getLocalHost().getHostName()));
        } catch (Exception e) {
        }
    }
}

public static class MyTaskResult implements Serializable  {
    private MyTaskResult() {}

    public GregorianCalendar Time = new GregorianCalendar();
    public String MachineName;
    public long TickCount;

    public MyTaskResult(String machineName) {
        Time = new GregorianCalendar();
        MachineName = machineName;
        TickCount = System.nanoTime();
    }
}

After a task has completed, the client gets a copy of the result object back. To use it, call the getResult() method of the task. Note, that because the result property is of the type java.lang.Object, it will have to be cast to the proper type.

Java  Copy imageCopy
MyTaskResult result = (MyTaskResult) job.getTasks().get(0).getResult();
// We have a copy of the object back
System.out.println("Time = " + result.Time);
System.out.println("MachineName = " + result.MachineName);
System.out.println("TickCont = " + result.TickCount);
Caution

The result property may be an Exception type if there was an uncaught exception while executing the task. For more information, see the Exceptions and Error Handling section below.

StandardOutput and StandardError

At times, the easiest way to pass data back is through the StandardOutput and StandardError properties. The only thing the task code needs to do is to call System.out.println and/or System.err.println. For example:

Java  Copy imageCopy
public static class WritesToStandardOutput extends Task {
    @Override
    public void execute() {
        try {
            System.out.println("Current Time in task is: " + new GregorianCalendar());
            System.out.println("Agent MachineName: " + InetAddress.getLocalHost().getHostName());
            System.out.println("Current Tick Count is: " + System.currentTimeMillis() );
        } catch (Exception e) {
        }
    }
}

The standard output and standard error is sent back to the client as a string. Access it like so:

Java  Copy imageCopy
System.out.println("Standard Output =" + job.getTasks().get(0).getStandardOutput());
Tip

The results of standard output are also displayed in the monitoring applications such as the Task Monitor. Looking at the standard output from the GUI is a convenient way to debug your application.

Console Output Appears In Monitoring Apps
Note

In the event of an unhandled exception, the Exception will be written as a string to standard error on the task's behalf.

Task Properties

Properties are yet another way to return data back from a task to the client. Task properties are stored internally as a hash table and can store user objects such as strings and integers. A task's properties object is returned back to the client after the task completes. Depending on an application's needs, task properties may be more convenient to update than the task's Result property.

One of the main advantage of Properties is that they are guaranteed to be returned to the client even if the task fails. This is not true with the task result. For instance, this example sets both the Result and Properties and then simulate an exception:

Java  Copy imageCopy
public static class PropertiesExample extends Task {
    @Override
    public void execute() {
        this.setProperty("Property1", 100);
        this.setProperty("Property2", "hundred");
        this.setResult("This won't get back to the scheduler as we will see");
        throw new RuntimeException("Task failure");
    }
}

On the client side, the Result property is an Exception while the properties object returned regardless.

Java  Copy imageCopy
// After the task failed,
System.out.println("Task status = " + job.getTasks().get(0).getTaskStatus());

// our Result property is an exception.
if (job.getTasks().get(0).getResult() instanceof Throwable) {
    System.out.println("Exception is " + job.getTasks().get(0).getResult());
}

// But we can get the properties object.
System.out.println("Property1: " + (Integer) job.getTasks().get(0).getProperty("Property1"));
System.out.println("Property2: " + (String) job.getTasks().get(0).getProperty("Property2"));

Aside from a guaranteed return after an exception, task properties should only be used if they are more convenient to use than the Result object.

Caution

Unlike Task.Result, there are only a small set of supported data types. Use only string, int, double, and byte[].

Exceptions and Error Handling

Tasks can fail or not complete successfully for a number of reasons. The most common reason for a failure is an uncaught exception in a tasks's code. Fortunately, the task's exception is handled and information is returned back to the client for error handling.

Task Failure

If a task fails, the Result property of the task will be the Exception object thrown in the task. The TaskStatus will be set to Failed. Also, the StandardError will include the stack trace of the exception. Here is an example that checks for task failure and inspects the Exception object.

Java  Copy imageCopy
if ((job.getTasks().get(0).getTaskStatus() == TaskStatus.FAILED) || (job.getTasks().get(0).getTaskStatus() == TaskStatus.ENVIRONMENT_ERROR)) {
    Throwable taskException = (Throwable) job.getTasks().get(0).getResult();
    if (taskException != null) {
        System.out.println("Exception message is: " + taskException.getMessage());
        System.out.println("StandardError also has the stack trace: " + job.getTasks().get(0).getStandardError());
    }
}
Note

As with most objects, the Exception object must be serializable. If an Exception object is not serializable, a generic Exception object will be created that includes the error message of the original exception.

Task Environment Failure

Similar to a task failure, when a task environment fails the task's result is the uncaught exception that was thrown. The TaskStatus is set to EnvironmentError. A task can only run after a task environment is sucessfully setup, so if a task environment fails to setup, the task does not run.

Task Cancellation

If a task gets canceled, information on why it was canceled is available. Check the task's TaskCancellationMessage and the TaskCancellationReason. Usually, some useful information will be provided in the TaskCancellationMessage; this normally includes an indication of the user who canceled the job.

Java  Copy imageCopy
if (job.getTasks().get(0).getTaskStatus() == TaskStatus.CANCELED) {
    if (job.getTasks().get(0).getTaskCancellationMessage() != null) {
        System.out.println("Task was canceled. Message was: " + job.getTasks().get(0).getTaskCancellationMessage());
    }
}

Putting it all together

Below is a code snippet that synthesizes the different ways data can be sent back to the client from a task, as described in this section. The following is a common pattern showing how each of the task statuses is handled after a task completes. Take note that during development, when code is not as well tested and errors are more likely to occur, the cases where a task could fail should always be handled.

Java  Copy imageCopy
// Typical submit and wait pattern....
job.addTask(task);
job.submit();
job.waitUntilDone();

// After the task completes...
if (task.getTaskStatus() == TaskStatus.COMPLETED) {
    // Task ran without throwing an uncaught exception.
    // This is the only state where your Result object is guaranteed to be your user defined result.
    System.out.println("Task completed at " + task.getProperty(TaskProperties.HOST_END_TIME));
    System.out.println("Result: " + task.getResult());
} else if (task.getTaskStatus() == TaskStatus.FAILED) {
    // Task.execute threw an uncaught exception.
    // The result object is the exception that was not caught.
    System.out.println(String.format("Task (%s) threw an exception during Task.execute", task.getClass().getName()));
    System.out.println("Exception: " + task.getResult());
    System.out.println("StandardError with callstack: " + task.getStandardError());
} else if (task.getTaskStatus() == TaskStatus.ENVIRONMENT_ERROR) {
    // TaskEnvironment.setup threw an uncaught exception.
    // The result object is the exception that was not caught.
    System.out.println(String.format("TaskEnvironment (%s) thew an exception during TaskEnvironment.setup", job.getTaskEnvironment().getClass().getName()));
    System.out.println("Exception: " + task.getResult());
    System.out.println("StandardError with callstack: " + task.getStandardError());
} else if (task.getTaskStatus() == TaskStatus.TIMED_OUT) {
    // Task execution exceeded the value specified in Job.TaskExecutionTimeout
    // This should only be handled if you specify a value for Job.TaskExecutionTimeout
    System.out.println("Task execution exceeded the specified execution timeout");
    System.out.println("TaskExecutionTimeout was " + job.getTaskExecutionTimeout());
} else if (task.getTaskStatus() == TaskStatus.CANCELED) {
    // Task was canceled with Job.Cancel or by the user (for instance, the UI).
    // This should usually be handled if it is possible that users can cancel your task.
    System.out.println("Task was canceled");
    if (task.getTaskCancellationReason() == TaskCancellationReason.DIRECT) {
        System.out.println("User who canceled the task was: " + task.getTaskCancellationMessage());
    }
} else {
    // Any other state is not a final state, that is the task is still transitioning.
}

See Also