Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Flowchart
chain_resource_lock [label="Job Chain\nimplements\na Resource Lock Provider",fillcolor="orange"]
job_manage_resource_lock [label="Job Manage Resource Lock",fillcolor="lightskyblue"]
resource_lock_available [shape=diamond,label="Resource Lock available?",fillcolor="white"]
 
chain_resource_lock_consumer_1 [label="Job Chain\nimplements a\nResource Lock Consumer",fillcolor="orange"]
job_request_resource_lock_1 [label="Job Request Resource Lock",fillcolor="lightskyblue"]
job_step_1_1 [label="Job Step 1",fillcolor="lightskyblue"]
job_step_1_2 [label="Job Step 2",fillcolor="lightskyblue"]

chain_resource_lock_consumer_2 [label="Job Chain\nimplements a\nResource Lock Consumer",fillcolor="orange"]
job_request_resource_lock_2 [label="Job Request Resource Lock",fillcolor="lightskyblue"]
job_step_2_1 [label="Job Step 1",fillcolor="lightskyblue"]
job_step_2_2 [label="Job Step 2",fillcolor="lightskyblue"]

order_1A [shape="ellipse",label="Order 1A",fillcolor="violet"]
order_1B [shape="ellipse",label="Order 1B",fillcolor="violet"]
order_2A [shape="ellipse",label="Order 2A",fillcolor="violet"]
order_2B [shape="ellipse",label="Order 2B",fillcolor="violet"]

shadow_order_1A [shape="ellipse",label="Shadow Order 1A",fillcolor="violet"]
shadow_order_1B [shape="ellipse",label="Shadow Order 1B",fillcolor="violet"]
shadow_order_2A [shape="ellipse",label="Shadow Order 2A",fillcolor="violet"]
shadow_order_2B [shape="ellipse",label="Shadow Order 2B",fillcolor="violet"]

order_suspend [label="Suspend Original Order",fillcolor="white"]
order_resume [label="Resume Original Order for Next Job",fillcolor="white"]

chain_resource_lock_consumer_1 -> order_1A
chain_resource_lock_consumer_1 -> order_1B
order_1A -> job_request_resource_lock_1 -> job_step_1_1
order_1B -> job_request_resource_lock_1 -> job_step_1_2
job_request_resource_lock_1 -> shadow_order_1A
job_request_resource_lock_1 -> shadow_order_1B
 
chain_resource_lock_consumer_2 -> order_2A
chain_resource_lock_consumer_2 -> order_2B
order_2A -> job_request_resource_lock_2 -> job_step_2_1
order_2B -> job_request_resource_lock_2 -> job_step_2_2
job_request_resource_lock_2 -> shadow_order_2A
job_request_resource_lock_2 -> shadow_order_2B
 
chain_resource_lock -> shadow_order_1A
chain_resource_lock -> shadow_order_1B
chain_resource_lock -> shadow_order_2A
chain_resource_lock -> shadow_order_2B
shadow_order_1A -> job_manage_resource_lock
shadow_order_1B -> job_manage_resource_lock
shadow_order_2A -> job_manage_resource_lock
shadow_order_2B -> job_manage_resource_lock

job_manage_resource_lock -> resource_lock_available
resource_lock_available -> order_resume [label=" yes "]
resource_lock_available -> order_suspend [label=" no "]
order_resume -> job_step_1_1 -> job_step_1_2
order_resume -> job_step_2_1 -> job_step_2_2

Implementation

Components

Job: request_resource_lock

  • This job can be used by resource lock consumers as the first job node in a The solution implements a job named sorter that can be added at the start of any job chain.
  • This job implements a spooler_process() function that suspends all incoming orders.
  • This job is configured for a single task and with an idle timeout attribute. This means that it will execute incoming orders sequentially.
  • Having received the last available order this job will wait for the duration specified with the idle_timeout attribute for new orders. 
    • The idle timeout is configured using, for example <job idle_timeout="10"> with the sorter job definition.
    • Once the idle timeout has expired this job will execute its spooler_exit() function and then sort and move all orders that have previously been suspended.
      • Sorting is done in alphabetical order.
      • The orders are moved to the next job chain node that follows the sorter job in the job chain.
  • The download example uses a job chain named job_chain1 that includes the job nodes for the sorter job and a hello job. This job chain accepts ad hoc orders that are added by JOC and it can easily be modified to watch for incoming files and to create an order for each file.
  • Hint: to re-use the sorter job you can:
    • store the job in a central folder and reference the job in individual job chains.
    • move the job's JavaScript code to a central location and use an appropriate <include> element for individual job scripts.

Job: request_resource_lock

...

  • The job has no special job script implementation.

    Image Added

  • The job makes use of the Monitor request_resource_lock.

    Image Added

Monitor: request_resource_lock

  • This Monitor implements a pre-processing script for jobs that request resource locks.
  • The monitor is used by the above request_resource_lock job and can be assigned to any individual job node of a job chain that requires a resource lock.
Code Block
languagejs
titleMonitor request_resource_lock
collapsetrue
function spooler_process_before() {
 
    var	resourceJobChainParamDefault = "/resource_lock_provider/resource_lock_provider";
    var resourceLockJobChainParam = "resource_job_chain";
    var resourceLockNameParam = "resource_lock";
    var resourceLockWakeUpParam = "resource_lock_wake_up";

	var order = spooler_task.order;
    var params = spooler.create_variable_set();
  		params.merge( spooler_task.params );
  		params.merge( order.params );

    // name of the requested resource: explicitely set by parameter or assuming the current job chain path
    var resourceLock = params.value( resourceLockNameParam );
    if ( !resourceLock ) {
		resourceLock = order.job_chain.path;
	}

    // name of the job chain that handles resource locks
    var resourceJobChainName = params.value( resourceLockJobChainParam );
    if ( !resourceJobChainName ) {
    	resourceJobChainName = resourceJobChainParamDefault;
    }

	// order wake up parameter indicates that order has acquired resource lock
    if ( params.value( resourceLockWakeUpParam ) == "yes" ) {
		spooler_log.info( ".. order acquired resource lock: " + resourceLock );
		return true;
    } else if ( params.value( resourceLockWakeUpParam ) == "no" ) {
		spooler_log.info( ".. order suspended and waiting for resource lock: " + resourceLock );
    	order.state = order.job_chain_node.state;
		order.suspended = true;
		return false;
	}

    var resourceJobChain = spooler.job_chain( resourceJobChainName );
    var resourceOrder = spooler.create_order();

    var resourceParams = spooler.create_variable_set();
    resourceParams.set_var( "requestor_job_chain", order.job_chain.path );
    resourceParams.set_var( "requestor_order", order.id );
    resourceOrder.params = resourceParams;

	resourceOrder.title = resourceLock;
	resourceOrder.at = "now+2";

...

Monitor: request_resource_lock

  • This Monitor implements a pre-processing script for jobs that request resource locks.
  • The monitor is used by the above request_resource_lock job and can be assigned to any individual job node of a job chain that requires a resource lock.
Code Block
languagejs
titleMonitor request_resource_lock
collapsetrue
function spooler_process_before() {
 
    var	resourceJobChainParamDefault = "/resource_lock_provider/resource_lock_provider";
    var resourceLockJobChainParam = "resource_job_chain";
    var resourceLockNameParam = "resource_lock";
    var resourceLockWakeUpParam = "resource_lock_wake_up";

	var order = spooler_task.order;
    var params = spooler.create_variable_set();
  		params.merge( spooler_task.params );
  		params.merge( order.params );

    // name of the requested resource: explicitely set by parameter or assuming the current job chain path
    var resourceLock = params.value( resourceLockNameParam );
    if ( !resourceLock ) {
		resourceLock = order.job_chain.path;
	}

    // name of the job chain that handles resource locks
    var resourceJobChainName = params.value( resourceLockJobChainParam );
    if ( !resourceJobChainName ) {
    	resourceJobChainName = resourceJobChainParamDefault;
    }

	// order wake up parameter indicates that order has acquired resource lock
    if ( params.value( resourceLockWakeUpParam ) == "yes" (order.job_chain.path + "/" + order.id).length <= 100 ) {
		spooler_log.info( ".. order acquired resource lock: " + resourceLock );
		return trueresourceOrder.id = order.job_chain.path + "/" + order.id;
    } else

  if ( paramsresourceJobChain.valueadd_order( resourceLockWakeUpParamresourceOrder );
 == "no" ) {
		spooler_log.info( ".. order suspended and waiting for requested resource lock: " + resourceLock );

	params.set_var( resourceLockWakeUpParam, "no"  	);
    order.state = order.job_chain_node.state;

		order.suspended  = true;
		return false;
	}

    var resourceJobChain = spooler.job_chain( resourceJobChainName );
    var resourceOrder = spooler.create_order();
 // always suspend current order, it will be waked up by the requested resource lock
    varorder.suspended resourceParams = spooler.create_variable_set();
    resourceParams.set_var( "requestor_job_chain", order.job_chain.path );
    resourceParams.set_var( "requestor_order", order.id );
    resourceOrder.params = resourceParams;

	resourceOrder.title = resourceLock;
	resourceOrder.at = "now+3";

    if ( (order.job_chain.path + "/" + order.id).length <= 100 ) {
		resourceOrder.id = order.job_chain.path + "/" + order.id;
    } 

    resourceJobChain.add_order( resourceOrder );
    spooler_log.info( ".. order requested resource lock: " + resourceLock );

	params.set_var( resourceLockWakeUpParam, "no" );
    order.state = order.job_chain_node.state;

    // always suspend current order, it will be waked up by the requested resource lock
    order.suspended = true;

	return false;
}

Configuration

...

  • The interval is 60s per default
  • The maximum number of retries is 1440 which defaults to a lifetime of 24 hrs. for a resource lock.
= true;

	return false;
}

Configuration

  • Use the sample job chain test_case_1 from the Resource Lock Consumer sample or any individual job chain and assign the job /resource_lock_provider/request_resource_lock as the first job node of the job chain. This configuration will guarantee that all newly created orders that are added to the begin of the job chain will be started after any predecessor orders completed the job chain.

    Image Added 
  • Should resource lock consistency be required for later job nodes in a job chain, i.e. if orders are created not for the begin of a job chain but for later job nodes, e.g. when using split job nodes, then assign the monitor /resource_lock_provider/request_resource_lock to the respective jobs:

    Image Added 
     
  • The repeat interval for which resource locks are checked is configured with the job manage_resource_lock of the resource lock provider.
    • The interval is 60s per default
    • The maximum number of retries is 1440 which defaults to a lifetime of 24 hrs. for a resource lock.
  • The configuration is provided like this:

    Image Added 

Hints

  • When requesting a resource lock by use of the request_resource_lock monitor then 
    • a delay of 2s is applied for the manage_resource_lock job to process the shadow order. A minimum delay is required to guarantee synchronization.
    • for shell jobs an error message will be added to the order log when the order is initially suspended. This message is not harmful and can be ignored. For API jobs no errors or warnings are raised. We recommend that you use the request_resource_lock job as a first job node of your job chain and use the monitor for subsequent job nodes only.
  • The lifetime of a resource lock is limited by the duration that is covered with the setback interval of the manage_resource_lock job that defaults to 24 hrs.
  • If you make frequent use of resource locks then you should consider to pre-load the manage_resource_lock job by use of the setting <job min_tasks="1"/> which results in the job to react immediately to incoming orders without having to load a JVM for each execution of this job.
  • When operating the Resource Lock Provider job chain in a different location than the directory ./config/live/resource_lock_provider then the following settings have to be adjusted:
    • From the Resource Lock Provider the request_resource_lock monitor script specifies the path of the provider job chain.
    • From the samples for the Resource Lock Consumer
      • the job chains test_case_1 and test_case_1A both assign the job /resource_lock_provider/request_resource_lock as the first job node.
      • the job chain test_case_2 makes use of jthe obs job_step_1_resource_lock and job_step_2_resource_lock that are assigned the monitor location in /resource_lock_provider/request_resource_lock.

Usage

  • Run test case 1: Check resource lock on first job step
    • The job chain test_case_1 makes use of the /resource_lock_provider/request_resource_lock job as the first job node.
    • No parameterization is used, therefore the scope of the resource lock is the current job chain that is forced to process order sequentially.
    • Adding multiple orders to this job chain causes all orders to be processed only after predecessor orders completed the job chain.
      • Start the orders test_case_1-1, ..., test_case_1-3 by use of JOC.
      • Add any number of new orders by use of JOC with the Add Order context menu.
  • Run test case 1A:  
    • The job chain test_case_1A is a copy of test_case_1 but makes use of the same resource lock as test_case_1
    • The orders test_case_1A-1, ..., test_case_1A-3 use the parameter resource_lock with the value /resource_lock_consumer/test_case_1 therefore forcing order for both job chains to be processed sequentially:
      • Start the orders test_case_1-1, ..., test_case_1-3 by use of JOC that will run for job chain test_case_1.
      • Start the orders test_case_1A-1, ..., test_case_1A-3 by use of JOC that will run in job chain test_case_1A but are synchronized with orders of job chain test_case_1.
  • Run test case 2:
    • The job chain test_case_2 makes use of the jobs job_step_1_resource_lock and job_step_2_resource_lock. Both jobs are assigned the request_resource_lock monitor. The above-mentioned initial job node request_resource_lock is not used as the individual jobs would anyway make use of the same monitor.
    • Adding multiple orders to this job chain causes orders to behave sequentially as for test case 1:
      • Start the orders test_case_2-1, ..., test_case_2-3 by use of JOC.
      • Add any number of new orders by use of JOC with the Add Order context menu

...

Hints

  • When requesting a resource lock by use of the request_resource_lock monitor then a delay of 3s is applied for the manage_resource_lock job to process the shadow order. A minimum delay is required to guarantee synchronization.
  • The lifetime of a resource lock is limited by the duration that is covered with the setback interval of the manage_resource_lock job that defaults to 24 hrs.
  • If you make frequent use of resource locks then you should consider to pre-load the manage_resource_lock job by use of the setting <job min_tasks="1"/> which results in the job to react immediately to incoming orders without having to load a JVM for each execution of this job.

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.
  • Both orders will be suspended at the first node of the job chain.
  • After an idle timeout of 10s both orders will be moved to the next job node in the job chain. 
    • This time the orders will be processed in ascending alphabetical order
      • .