You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 16 Next »

Scope

  • How to sort a number of orders that have been added to a job chain and to force serialized processing in a predefined order?
  • The solution outline includes a job that is added to the top of the job chain and that would 
    • suspend all incoming orders until a predefined idle timeout is reached and no more orders are expected
    • sort the orders in alphabetical sequence of the order id and reinsert them to the next job node in the job chain.
  • Reference: https://sourceforge.net/p/jobscheduler/discussion/486122/thread/a66295bb/

Solution

  • Download sort_orders.zip
  • Extract the archive to any folder within the ./config/live folder of your JobScheduler installation.
  • The archive will extract the files included to a folder sort_orders. 
  • You can store the sample files to a different folder, the solution does not make use of specific folder names.

Pattern

Implementation

Components

  • The solution implements a job sorter that can be added to the top of any job chain.
    • This job implements a spooler_process() function that suspends all incoming orders.
    • This job is configured for one task and with an idle timeout attribute, i.e. it executes incoming orders sequentually.
    • After the last order this job waits for the duration specified with the idle_timeout attribute for new orders. 
      • The idle timeout is configured by <job idle_timeout="10"> with the sorter job definition.
      • With the idle timeout being expired this job will execute its spooler_exit() function and will sort all orders that have previously been suspended.
        • Sorting is done in alphabetical order.
        • The orders are reinserted to the next job node that follows the sorter job in the job chain.
  • The sample included makes use of a job chain job_chain1 that includes the job nodes for the sorter job and a hello job.

 

Job sorter
var jobChainPath = null;
var jobChainNodeState = null;
var jobChainNodeNextState = null;

function spooler_init() {
  spooler_log.info( ".. performing spooler_init()" );
  jobChainPath = spooler_task.order.job_chain.path;
  jobChainNodeState = spooler_task.order.job_chain_node.state;
  jobChainNodeNextState = spooler_task.order.job_chain_node.next_state;


  return true;
}


function spooler_process() {
  var rc = true;
  // suspend all orders, sorting is done on spooler_exit()
  spooler_log.info( ".. suspending current order" );
  spooler_task.order.suspended = true;
  spooler_task.order.state = jobChainNodeState;


  return rc;
}


function spooler_exit() {
  spooler_log.info( ".. peforming spooler_exit()" );
  var rc = true;
  var orderList = Array();


  // select all orders of the current job node
  var response = spooler.execute_xml( "<show_job_chain job_chain='" + jobChainPath + "' what='job_chain_orders'/>" );
  var orderDOM = new Packages.sos.xml.SOSXMLXPath( new java.lang.StringBuffer( response ) );
  var orderNodes = orderDOM.selectNodeList( "/spooler/answer/job_chain/job_chain_node[@state = '" + jobChainNodeState + "']/order_queue/order" );


  // traverse orders and check if orders are completed
  for( orderIndex=0; orderIndex<orderNodes.getLength(); orderIndex++ ) {
    var orderNode = orderNodes.item(orderIndex);
    var orderID = orderDOM.selectSingleNodeValue( orderNode, "@id" );
    if (orderID == null) {
      continue;
    }
    spooler_log.info( ".... order found: " + orderID );
    orderList.push( orderID );
  }


  // alphabetical string sort
  orderList.sort(function(a, b){return (a > b) - (a < b) });
  // numeric sort
  // orderList.sort(function(a, b){return b - a) });


  for(i=0; i<orderList.length; i++) {
    spooler_log.info( ".... moving order: " + orderList[i] );
    var response = spooler.execute_xml( "<modify_order job_chain='" + jobChainPath + "' order='" + orderList[i] + "' state='" + jobChainNodeNextState + "' suspended='no'/>" );
    var orderDOM = new Packages.sos.xml.SOSXMLXPath( new java.lang.StringBuffer( response ) );
    var errorCode = orderDOM.selectSingleNodeValue( "//ERROR/@code" );
    var errorText = orderDOM.selectSingleNodeValue( "//ERROR/@text" );
    if ( errorCode || errorText ) {
      spooler_log.error( "........ modify order state response: errorCode=" + errorCode + ", errorText=" + errorText );
      rc = false;
    }  
  }


  return rc;
}

Usage

  • Add two orders to the job_chain1 job chain. 
    • Use an order id in descending alphabetical order, e.g. "cba" for the order id of the first order and "abc" for the order id of the second order.
  • Both orders will be suspended in the first node of the job chain.
  • After 10s both orders are reinserted to the next job node in the job chain. 
    • This time the orders are processed in ascending alphabetical order.

 

  • No labels