time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

spawn.js (3602B)


      1 /**
      2 * @license Apache-2.0
      3 *
      4 * Copyright (c) 2018 The Stdlib Authors.
      5 *
      6 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *    http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 */
     18 
     19 'use strict';
     20 
     21 // MODULES //
     22 
     23 var run = require( 'child_process' ).spawn;
     24 var logger = require( 'debug' );
     25 var cwd = require( '@stdlib/process/cwd' );
     26 var proc = require( './process.js' );
     27 
     28 
     29 // VARIABLES //
     30 
     31 var debug = logger( 'parallel:worker:spawn' );
     32 
     33 
     34 // MAIN //
     35 
     36 /**
     37 * Runs a script by spawning a child process.
     38 *
     39 * @private
     40 * @param {string} cmd - command to run
     41 * @param {string} script - script filepath
     42 * @param {Callback} clbk - callback to invoke after a child process closes
     43 * @returns {Process} child process
     44 */
     45 function spawn( cmd, script, clbk ) {
     46 	var child;
     47 	var args;
     48 	var opts;
     49 	var err;
     50 
     51 	debug( 'Creating child process...' );
     52 	args = [ script ];
     53 	opts = {
     54 		'cwd': cwd(),
     55 		'env': proc.env,
     56 		'shell': false, // don't run the command inside a shell
     57 		'stdio': 'inherit' // use stdio of worker process
     58 	};
     59 	if ( proc.env.WORKER_UID ) {
     60 		opts.uid = parseInt( proc.env.WORKER_UID, 10 );
     61 	}
     62 	if ( proc.env.WORKER_GID ) {
     63 		opts.gid = parseInt( proc.env.WORKER_GID, 10 );
     64 	}
     65 	child = run( cmd, args, opts );
     66 
     67 	child.on( 'error', onError );
     68 	child.on( 'close', onClose );
     69 	child.on( 'exit', onExit );
     70 	child.on( 'disconnect', onDisconnect );
     71 
     72 	debug( 'Child process created. pid: %d.', child.pid );
     73 	return child;
     74 
     75 	/**
     76 	* Callback invoked upon child process close.
     77 	*
     78 	* @private
     79 	* @param {(number|null)} code - exit code
     80 	* @param {(string|null)} signal - termination signal
     81 	* @returns {void}
     82 	*/
     83 	function onClose( code, signal ) {
     84 		debug( 'Child process closed. Code: %d. Signal: %s. pid: %d.', code, signal, child.pid );
     85 		processExit( code, signal );
     86 		if ( err ) {
     87 			return clbk( err );
     88 		}
     89 		clbk( null, child.pid, script );
     90 	}
     91 
     92 	/**
     93 	* Callback invoked upon child process exit.
     94 	*
     95 	* @private
     96 	* @param {(number|null)} code - exit code
     97 	* @param {(string|null)} signal - termination signal
     98 	*/
     99 	function onExit( code, signal ) {
    100 		debug( 'Child process exited. Code: %d. Signal: %s. pid: %d.', code, signal, child.pid );
    101 		processExit( code, signal );
    102 	}
    103 
    104 	/**
    105 	* Callback invoked upon child process disconnect.
    106 	*
    107 	* @private
    108 	*/
    109 	function onDisconnect() {
    110 		debug( 'Child process disconnected. pid: %d.', child.pid );
    111 	}
    112 
    113 	/**
    114 	* Callback invoked upon child process error.
    115 	*
    116 	* @private
    117 	* @param {Error} error - error object
    118 	*/
    119 	function onError( error ) {
    120 		debug( 'Child process error: %s. pid: %d.', error.message, child.pid );
    121 		clbk( error );
    122 	}
    123 
    124 	/**
    125 	* Processes process exit values and sets the `err` state.
    126 	*
    127 	* @private
    128 	* @param {(number|null)} code - exit code
    129 	* @param {(string|null)} signal - termination signal
    130 	*/
    131 	function processExit( code, signal ) {
    132 		if ( err ) {
    133 			return;
    134 		}
    135 		if ( code !== null && code !== 0 ) {
    136 			err = new Error( cmd+' '+script+' failed with exit code: '+code+'.' );
    137 		} else if ( signal !== null ) {
    138 			err = new Error( cmd+' '+script+' failed due to termination signal: '+signal+'.' );
    139 		}
    140 		if ( err ) {
    141 			err.code = code;
    142 			err.signal = signal;
    143 		}
    144 	}
    145 }
    146 
    147 
    148 // EXPORTS //
    149 
    150 module.exports = spawn;