Tutorial

Compute-Service-made-easy

Introduction

The SAS Viya compute service API covers many different use cases. The simplest and most common use case is to run a SAS job and view the ODS output, log, listing and browse the generated tables.

@sassoftware/restaflib library has a set of methods specifically designed to address this very common usage pattern.

Summary of methods

  • computeSetup - this creates a compute session

  • computeRun - this executes the specified sas code. Setup macros are passed in as standard javascript object.

  • computeResults - retrieve output - logs, ods, listing and list of tables created in that run

  • computeFetchData - scroll thru and fetch data form one of the tables.

Usage

computeSetup

This method creates a compute service session.

Syntax

let session = await restaflib.computeSetup(store, contextName,logonPayload,sessionPayload);

The parameters are:

  • store - restaf store object
  • contextName - (optional) If not specified it will default to SAS Job Execution context
  • logonPayload - specify this if you want computeSetup to logon to the server. See this for details.
  • sessionPayload - specify this if you want to pass a payload to the create session (ex: { headers: {...}})

computeRun

This method executes the specified code on the server
let computeSummary = await restaflib.computeRun(store, session, src, macros)

The parameters are:

  • store - restaf store object
  • session - The session object obtained thru the computeSetup method
  • src - A string containing the source code to be executed.
  • macros - (optional) A javascript object that is sent to the server as macros. For example if this object is {lib: 'sasuser', data: 'mydata'} the following macros are prepended to the source code
  • timeout - (optional) This is timeout(secs) used by the state end point for long polling(default is 5secs)

    Checking completion status

    Check computeSummary.SASJobStatus for completion status. The value will be one of the following:

    • completed - job ran with no warnings or errors
    • warning - job ran to completion but check for warning in the log
    • error - job had errors
    • failed - the job failed for other reasons.

This method uses the long polling in compute server to wait on completion. The result from the computeRun method are used to retrieve specific results using the following methods.

computeResults

This method is used to get the ods output, log, listing and the list of tables.

Syntax

 let result = await restaflib.computeResults(store, computeSummary, type)

The parameters are:

  • store - The restaf store
  • computeSummary - The output from restaflib.computeRun
  • type - A string with one of the following values ods|log|listing. Based on this option different results are returned

The results based on the value of type are:

  • ods - This will return a string that has the ODS output. This html can be passed to some component for display
  • log - This will return all the log for this particular job. The content is an array of objects that follows the media type for [loglines] log lines
  • listing - This will return all the listings for this particular job. This has the same format as the log
  • tables - This returns an array with the names of the tables returned by the job. Use this name to retrieve the actual records using the restaflib.computeFetchData method described below

computeFetchData

Use this method to page thru the records of the tables returned by the computeRun method. This method takes advantage of the standard scrolling rels and links.

Syntax

let result = await restaflib.computeFetchData(store, computeSummary, tablename, direction);

The parameters are:

  • store - restaf store
  • computeSummary - the output from restaflib.computeRun
  • tablename - the name of the table returned (see computeResults method above).
  • direction - a string to indicate which direction to scroll and get records. If not specified the first set of records are returned. The valid values of this parameter depend on what was returned in the scrollOptions field of the result see below

The result from the computeFetchData has the following schema

{
  rows: An array of data rows - and each data row is an array of values for that row,
  columns: The [standard schema](https://developer.sas.com/apis/rest/Compute/#tocScolumn") for the columns</
  scrollOptions: An array of strings with possible values for the next scroll. These usually are one or more of the following values: first, next, prev, last. Use this to move through the data set.
} 

Example

Also see this simple web application with user input for macros.

async function test_computeRun () {
  
  let computeSession = await computeSetup(store);

  /* prep input */
  let macros = {maxRows: 500};
  let src =  `ods html style=barrettsblue;
  data work.dtemp1;
      array x{10};  
      do j = 1 to &maxRows;  
        do i = 1 to 10;  
          x{i} = i * 10;  
          end;  
       output;  
       put _ALL_;  
      end;  
      run;  
      proc print;run;  
      ods html close;`;
  

  // Run the SAS job
  let computeSummary = await restaflib.computeRun(store, computeSession, src,  macros);

  // Check status of job
  let status = computeSummary.SASJobStatus;
  if ( status === 'failed' || status ==='running) {
     console.log('Job  ended with status of ', status);
  }
  // Get log, listing, ods and list of tables
  let log = await restaflib.computeResults(store, computeSummary, 'log');
  let list = await restaflib.computeResults(store, computeSummary, 'listing');
  let ods = await restaflib.computeResults(store, computeSummary, 'ods');
  let tables = await restaflib.computeResults(store, computeSummary, 'tables');

  // Scroll thru one of the tables
  let data = await restaflib.computeFetchData(store,computeSummary, 'DTEMP1');
  console.log(data.columns);
  console.log(`First row in set: ${data.rows[0]}`);
  console.log(`Last row in set: ${data.rows[data.rows.length-1]}`);
  console.log(`Pagination links: ${data.scrollOptions}`);
  console.log('\n');
  
  do {
    data = await restaflib.computeFetchData(store,computeSummary, 'DTEMP1', 'next');
    if (data !== null) {
     // print.object(computeSummary.tables['DTEMP1'].current.raw('data', 'results','links'), 'pagination links');
      console.log(`First row in set: ${data.rows[0]}`);
      console.log(`Last row in set: ${data.rows[data.rows.length-1]}`);
      console.log(`Pagination links: ${data.scrollOptions}`);
      console.log('\n');
    }
  } while (data != null);

  // Now scroll backwards to the top

  do {
    data = await restaflib.computeFetchData(store,computeSummary, 'DTEMP1', 'prev');
    if (data !== null) {
      console.log(data.rows[0]);
      console.log(JSON.stringify(data.scrollOptions, null,4));
    }
  } while (data != null);

// Delete session
  await store.apiCall(computeSession.links('delete'));
}

Monitoring Progress of the job

The progress of the job can be monitored by specifying the checkStatus parameter and a context object. This function will be called everytime the state end point sends a response.The time interval is controlled by the timeout parameter. The context object will be passed to it.

The parameters to the checkStatus function are:

  • state - a string that has the current status returned from a state api end point. Usually these are 'completed', 'running', 'error'.

  • context - the context object passed to computeRun.

  • returns - for normal processing return the incoming state. If you want to stop waiting on the server to complete, return some other string(ex: 'exit').

Sample checkStatus


function checkStatus(state, context) {
   context.tries = context.tries + 1;
   if (context.tries >= context.maxTries) {
    state= 'exit';
   } 
   return state;
}
let context = {
  tries: 0,
  maxTries: 200,
  code: null
}

let computeSummary = await restaflib.computeRun(store, computeSession, src,  macros,5, checkStatus, context);

if (computeSummary.SASJobStatus === 'exit') {
  // processing stopped due to checkStatus
  // do something here
} else {
  // do normal processing
}

Notes

restaflib relies on restaf

Setup

Web Applications

Include the following two script tags.

    <script src="https://unpkg.com/@sassoftware/restaf@next"></script>

    <script src="https://unpkg.com/@sassoftware/restaflib@next"></script>

Two globals restaf and restaflib will be available for use in your script tags.

Nodejs application

Install restaf and restaflib using the following command

    npm install @sassoftware/restaf@next @sassoftware/restaflib@next