简体   繁体   中英

Node.js - Watch spawned child's output for specific text

So, I'm using Node's child_process module to spawn an instance of elastic search. I need to check when the service is up and resolve() a promise when it is. This is how I am doing it right now:

const { join } = require('path');
const { spawn } = require('child_process');
const { createWriteStream } = require('fs');
const { Transform } = require('stream');

function start() {
  return new Promise(resolve => {
    const outStream = new Transform({
      transform(chunk, encoding, callback) {
        if (chunk.toString().includes('started')) resolve();
        this.push(chunk);
        callback();
      }
    });

    const logFile = createWriteStream(join(LOG_DIR, 'es.log'), 'w');
    const errorFile = createWriteStream(join(LOG_DIR, 'es.error.log'), 'w');

    outStream.pipe(logFile);

    child = spawn(
      ES_BAT_PATH,
      [],
      { cwd: process.cwd(), stdio: ['ignore', outStream, errorFile] }
    );
  });
}

Is this the best way ? (probably not) if not how should I go about this?

In general I would say this is a reasonable way to do this, but I see some problems here:

  • The chunks may not contain the whole word you're looking for, but it may fall in between the two (one chunk ends in 'sta' and the next starts with 'rted' .
  • After the initial find you still have a transform stream you don't actually need anymore
  • There's also the problem of unicode chars, but since you're looking for ' started ' you can omit that.

The first issue would be easily mitigated, by keeping the last portion after a space. For the second you need to unpipe the transform - so you'd end up with something like this:

const { join } = require('path');
const { spawn } = require('child_process');
const { createWriteStream } = require('fs');
const { Readable, PassThrough } = require('stream');

function start() {

    return new Promise(resolve => {
        const outStream = new PassThrough();
        let last;
        const lookupStream = new Readable({
            read(chunk, encoding, callback) {
                const ref = chunk.toString();
                if ((last + ref).includes('started')) {
                    outStream.unpipe(lookupStream);
                    resolve();
                }
                last = ref.replace(/^.* /, '');
                callback();
            }
        });

        const logFile = createWriteStream(join(LOG_DIR, 'es.log'), 'w');
        const errorFile = createWriteStream(join(LOG_DIR, 'es.error.log'), 'w');

        outStream.pipe(logFile);
        outStream.pipe(lookupStream);

        child = spawn(
            ES_BAT_PATH,
            [],
            { cwd: process.cwd(), stdio: ['ignore', outStream, errorFile] }
        );
    });
}

Another option is to use on('data' listener and remove it after the right chunk is found.

Lastly, my framework, scramjet would make this a little easier

const { join } = require('path');
const { spawn } = require('child_process');
const { createWriteStream } = require('fs');
const { StringStream } = require('scramjet');

function start() {

    const outStream = new PassThrough();
    const lookupStream = new StringStream();
    const logFile = createWriteStream(join(LOG_DIR, 'es.log'), 'w');
    const errorFile = createWriteStream(join(LOG_DIR, 'es.error.log'), 'w');

    outStream.pipe(logFile);
    outStream.pipe(lookupStream);

    child = spawn(
        ES_BAT_PATH,
        [],
        { cwd: process.cwd(), stdio: ['ignore', outStream, errorFile] }
    );

    return lookupStream
        .split('\n')                                    // split line by line
        .filter(x => x.includes('started'))             // check if line contains "started"
        .until(x => outStream.unpipe(lookupStream))     // end stream on first occurence
        .run();                                         // run and resolve on stream end
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM