Welcome to the Harris Geospatial product documentation center. Here you will find reference guides, help documents, and product libraries.


Harris Geospatial / Docs Center / Geospatial Services Framework / GSF Tutorial: Chaining Jobs

Geospatial Services Framework

GSF Tutorial: Chaining Jobs

GSF - Tutorial - Chaining Jobs

Chaining jobs refers to using the output of a completed job as input for the next job. In this way, a sequence of jobs can be chained together to implement a desired workflow or processing chain.

Chaining a Job


Chaining jobs together is as simple as passing the output from a job back in as input to the next job.

Here is an example output from a job that has completed:

GET /ese/jobs/1/status
...
"results": [
    {
        "name": "OUTPUT_RASTER",
        "value": {
            "url": "http://localhost:9191/ese/jobs/1/envitempfileFriApr01153633201618_1.dat",
            "factory": "URLRaster",
            "auxiliary_url": [
                "http://localhost:9191/ese/jobs/1/envitempfileFriApr01153633201618_1.hdr"
            ]
        }
    }
]
...

To use the output from this task in a new task, just set the INPUT_RASTER = OUTPUT_RASTER.value when submitting a new job.

http://localhost:9191/ese/services/ENVI/ISODataClassification/submitJob?INPUT_RASTER={%20%22url%22:%20%22http://localhost:9191/ese/jobs/1/envitempfileFriApr01153633201618_1.dat%22,%20%22factory%22:%20%22URLRaster%22,%20%22auxiliary_url%22:%20[%20%22http://localhost:9191/ese/jobs/1/envitempfileFriApr01153633201618_1.hdr%22%20]%20}

NOTE: This tutorial uses the ese-request-handler for submitting jobs and retrieving results.

Specifying the Correct URL


Follow-on jobs are supported using a parameter mapper. The parameter mapper reverse translates all output file paths into a web-friendly URL. Those web-friendly URLS can then be used as input and the parameter mapper translates them back into local file paths. If the parameter mapper is paired with a request handler, that URL facilitates downloading the data directly to a client. The ese-request-handler is configured to work with the envi-data-parameter-mapper to provide web-friendly download links and allow job results to be used as input to future jobs.

It is important to use this pattern when specifying file paths instead of just using the raw absolute file paths. Clients do not need to know where files are stored on the server, and they should not assume that the file location is fixed. Depending on which workspace manager is configured, the files may not exist. In a clustered environment, those files may not be available at the same file location. A common URL allows the server to manage the files. This way, the client can use a consistent reference to that file.

Chaining a Job Programmatically


This tutorial provides an example of chaining together two jobs. The first job uses the ISODATAClassification task to read a raster and output a classification image. That image is then passed as input to the second job, which uses the ClassificationImageToVector task to create a vector-format output representing the class regions of the output classification image. Information about the various available tasks is located at http://www.harrisgeospatial.com/docs.

This example assumes that the default configuration is being used. See the Getting Started tutorial for further information about configuration and running jobs.

The following code is written as a Node.js script. Add all code for this tutorial to a JavaScript file (ie chainJobs.js). Note: As in other tutorials, the full example code block is provided at the bottom of the page.

Create a function to submit a job:

var request = require('request'); // Use request module to make http requests easier.
function submitJob(task, params, cb) {
  request.post(
    {
      url : 'http://' + hostname + ':' + port +
            '/ese/services/ENVI/' + task + '/submitJob',
      json: params
    },
    function(err, resp) {
      var statusURL = 'http://' + hostname + ':' + port +
      resp.headers.location;
      poll(statusURL, cb);
    }
  );
}

Job Status


The submitJob function puts the job on the queue, but it does not wait for the job to finish. There are two approaches to waiting for the job to complete. For simplicity, this tutorial uses polling. This polling function takes the status URL from the submitJob function and queries it once per second until the job completes.

For another method of determining the job status, see the Server-Sent Events tutorial.

The polling function:

function poll(statusURL, cb) {
  function getStatus() {
    request(statusURL, function(err, res, data) {
      if (err) {
        console.log(err);
      } else {
        console.log(data);
        var json = JSON.parse(data);
        if (json.jobStatus === 'esriJobSucceeded') {
          cb(json.jobStatus === 'esriJobSucceeded', json);
        } else if (json.jobStatus === 'esriJobFailed') {
          console.log(json.jobStatus);
        } else {
          setTimeout(getStatus, 1000);
        }
      }
    });
  }
  getStatus();
}

Creating a Workflow


With the above functions available, it becomes easy to chain jobs together.

Using the above functions with this script programmatically runs ISODATAClassification and then ClassificationToShapeFile on a sample image included with ENVI.

var hostname = 'localhost';
var port = '9191';
var task1 = 'ISODATAClassification';
var params1 = {
  INPUT_RASTER: {
    url    : 'http://localhost:9191/ese/data/qb_boulder_msi',
    factory: 'URLRaster'
  }
};
var task2 = 'ClassificationToShapeFile';
var params2 = {
};
submitJob(task1, params1, function(success, data) {
  console.log(data);
  if (!success) {
    console.log('Task1 Failed!');
  } else {
    // Get the output of the completed job 
    var outputRaster = data.results.find(function(r){
      return r.name === 'OUTPUT_RASTER';
    }).value;
    console.log(outputRaster.url);
    // Use that output as input for the next job
    params2.INPUT_RASTER = outputRaster;
    submitJob(task2, params2, function(success2, data2) {
      console.log();
      console.log('********************************');
      console.log('Shapefile Generated Successfully');
      console.log('********************************');
    });
  }
});

To execute this script, start the server, create a JavaScript file (ie chainJobs.js) with the code in this tutorial, and run it with Node.js:

  node chainJobs.js

NOTE: The script has a dependency on the request module. Make sure to install that dependency first with npm install request

Full Example Code Block

Copy the following code into a chainJobs.js JavaScript file.

var request = require('request'); // Use request module to make http requests easier.
function submitJob(task, params, cb) {
  request.post(
    {
      url : 'http://' + hostname + ':' + port +
            '/ese/services/ENVI/' + task + '/submitJob',
      json: params
    },
    function(err, resp) {
      var statusURL = 'http://' + hostname + ':' + port +
      resp.headers.location;
      poll(statusURL, cb);
    }
  );
}
function poll(statusURL, cb) {
  function getStatus() {
    request(statusURL, function(err, res, data) {
      if (err) {
        console.log(err);
      } else {
        console.log(data);
        var json = JSON.parse(data);
        if (json.jobStatus === 'esriJobSucceeded') {
          cb(json.jobStatus === 'esriJobSucceeded', json);
        } else if (json.jobStatus === 'esriJobFailed') {
          console.log(json.jobStatus);
        } else {
          setTimeout(getStatus, 1000);
        }
      }
    });
  }
  getStatus();
}
var hostname = 'localhost';
var port = '9191';
var task1 = 'ISODATAClassification';
var params1 = {
  INPUT_RASTER: {
    url    : 'http://localhost:9191/ese/data/qb_boulder_msi',
    factory: 'URLRaster'
  }
};
var task2 = 'ClassificationToShapeFile';
var params2 = {
};
submitJob(task1, params1, function(success, data) {
  console.log(data);
  if (!success) {
    console.log('Task1 Failed!');
  } else {
    // Get the output of the completed job 
    var outputRaster = data.results.find(function(r){
      return r.name === 'OUTPUT_RASTER';
    }).value;
    console.log(outputRaster.url);
    // Use that output as input for the next job
    params2.INPUT_RASTER = outputRaster;
    submitJob(task2, params2, function(success2, data2) {
      console.log();
      console.log('********************************');
      console.log('Shapefile Generated Successfully');
      console.log('********************************');
    });
  }
});



© 2017 Exelis Visual Information Solutions, Inc. |  Legal
My Account    |    Buy    |    Contact Us