JPPF, java, parallel computing, distributed computing, grid computing, parallel, distributed, cluster, grid, cloud, open source, android, .net
JPPF, java, parallel computing, distributed computing, grid computing, parallel, distributed, cluster, grid, cloud, open source, android, .net
JPPF

The open source
grid computing
solution

 Home   About   Features   Download   Documentation   Forums 

Receiving notifications of node life cycle events

From JPPF 5.2 Documentation

Jump to: navigation, search

Contents

Main Page > Customizing JPPF > Node life cycle events

This plugin provides the ability to receive notifications of major events ocurring within a node, including node startup and termination as well as the start and completion of each job processing.

1 NodeLifeCycleListener interface

To achieve this, you only need to implement the interface NodeLifeCycleListener, which is defined as follows:

public interface NodeLifeCycleListener extends EventListener {
  // Called when the node has finished initializing,
  // and before it starts processing jobs
  void nodeStarting(NodeLifeCycleEvent event);

  // Called when the node is terminating
  void nodeEnding(NodeLifeCycleEvent event);

  // Called when the node has loaded a job header and before
  // the DataProvider or any of the tasks has been loaded
  void jobHeaderLoaded(NodeLifeCycleEvent event);

  // Called before the node starts processing a job
  void jobStarting(NodeLifeCycleEvent event);

  // Called after the node finishes processing a job
  void jobEnding(NodeLifeCycleEvent event);

  // Called after the node has sent the results of a job to the server and before it
  // receives the next job. The node is fully idle at this point
  void beforeNextJob(NodeLifeCycleEvent event);
}

If you do not wish to implement all the methods of this interface you may instead extend the convenience class NodeLifeCycleListenerAdapter, which provides an empty implementation of all the methods of the interface, and override only the methods you're interested in.

Each method in the listener receives an event of type NodeLifeCycleEvent, which provides the following API:

public class NodeLifeCycleEvent extends EventObject {
  // Get the object representing the current JPPF node
  public Node getNode()

  // The type of this event
  public NodeLifeCycleEventType getType()

  // Get the job currently being executed
  public JPPFDistributedJob getJob();

  // Get the tasks currently being executed
  public List<Task> getTasks();

  // Get the class loader used to load the tasks and
  // the classes they need from the client
  public AbstractJPPFClassLoader getTaskClassLoader()
}

Please note that the methods getJob(), getTasks() and getTaskClassLoader() will return null for the events of type “nodeStarting()” and may return null for “nodeEnding()” events, as the node may not be processing any job at the time these events occur. The type of the event is available as an instance of the typesafe enum NodeLifeCycleEventType, defined as follows:

public enum NodeLifeCycleEventType {
  // nodeStarting() notification
  NODE_STARTING,

  // nodeEnding() notification
  NODE_ENDING,

  // jobHeaderLoaded() notification
  JOB_HEADER_LOADED,

  // jobStarting() notification
  JOB_STARTING,

  // jobEnding() notification
  JOB_ENDING,

  // beforeNextJob() notification
  BEFORE_NEXT_JOB
}

You will also notice that the method getTasks() returns a list of Task<T> instances. Task<T> is the interface for all JPPF tasks, and can be safely cast to AbstractTask for all practical purposes.

JPPFDistributedJob is an interface common to client side jobs (see JPPFJob) and server/node side jobs. It provides the following methods, which can be used in the the NodeLifeCycleListener implementation:

public interface JPPFDistributedJob {
   // Get the user-defined display name for this job
   // This is the name displayed in the administration console
  String getName();

  // Get the universal unique id for this job
  String getUuid();

  // Get the service level agreement between the job and the server
  JobSLA getSLA();

  // Get the user-defined metadata associated with this job
  JobMetadata getMetadata();
}

Once the implementation is done, the listener is hooked up to JPPF using the service provider interface:

  • create a file in META-INF/services named org.jppf.node.event.NodeLifeCycleListener
  • in this file, add the fully qualified class name of your implementation of the interface
  • copy the jar file or class folder containing your implementation and service file to either the JPPF driver's class path, if you want it deployed to all nodes connected to that driver, or to the classpath of individual nodes, if you only wish specific nodes to have the add-on


Note regarding the jobHeaderLoaded() notification:

At the time this method is called, neither the DataProvider (if any) nor the tasks have been deserialized. This means that the tasks can reference classes that are not yet in the classpath, and you can add these classes to the classpath on the fly, for instance by calling NodeLifeCycleEvent.getTaskClasLoader(), then invoking the addURL(URL) method of the resulting AbstractJPPFClassLoader.


Here is a simple example illustrating the process. Our implementation of the NodeLifeCycleListener interface, which simply prints the events to the node's console:

package myPackage;

public class MyNodeListener extends NodeLifeCycleListenerAdapter {
  @Override
  public void nodeStarting(NodeLifeCycleEvent event) {
    System.out.println("node ready to process jobs");
  }

  @Override
  public void nodeEnding(NodeLifeCycleEvent event) {
    System.out.println("node ending");
  }

  @Override
  public void jobHeaderLoaded(NodeLifeCycleEvent event) {
    JPPFDistributedJob job = event.getJob();
    System.out.println("node loaded header for job '" + job.getId() +
      "' using task class loader " + event.getTaskClassLoader());
  }

  @Override
  public void jobStarting(NodeLifeCycleEvent event {
    JPPFDistributedJob job = event.getJob();
    System.out.println("node starting job '" + job.getName() + "' with " +
      event.getTasks().size() + " tasks");
  }

  @Override
  public void jobEnding(NodeLifeCycleEvent event) {
    System.out.println("node finished job '" + event.getJob().getName() + "'");
  }
}

Once this is done, we create the file META-INF/services/org.jppf.node.event.NodeLifeCycleListener with the following content:

myPackage.MyNodeListener

Our node listener is now ready to be deployed.


Related JPPF samples:

2 Error handler

It is now possible to provide an error handler for each NodeLifeCycleListener implementation. This error handler will process all uncaught Throwables raised during the execution of any of the listener's methods.

To setup an error handler on a NodeLifeCycleListener implementation, you just have to implement the interface NodeLifeCycleErrorHandler, defined as follows:

public interface NodeLifeCycleErrorHandler {
  // Handle the throwable raised for the specified event
  void handleError(
    NodeLifeCycleListener listener, NodeLifeCycleEvent event, Throwable t);
}

The listener parameter is the listener instance which threw the throwable. The event parameter is the notification that was sent to the listener; its getType() method will allow you to determine which method of the listener was called when the throwable was raised. The last parameter is the actual throwable that was raised.

When the NodeLifeCycleListener does not implement NodeLifeCycleErrorHandler, JPPF will delegate the error handling to a default implementation: DefaultLifeCycleErrorHandler.

Lastly, if an uncaught throwable is raised within the error handler itself, JPPF will handle it as follows:

  • if the logging level is “debug” or finer then the full stack trace of the throwable is logged
  • otherwise, only the throwable's class and message are logged
  • if the throwable is an instance of Error, it is propagated up the call stack
Main Page > Customizing JPPF > Node life cycle events

JPPF Copyright © 2005-2017 JPPF.org Powered by MediaWiki