Node.js - Wait until file is completely written

I'm using child_process to run wkhtmltopdf to build a PDF from an html document. I want to wait until wkhtmltopdf is finished processing the document into a PDF before I proceed. I think that reading from stdout to capture when wkhtmltopdf sends its done signal is the best way to do this, but the following code reports stdout to be empty at res.send(). How do I set up an event to fire when stdout gives me data?

Code:

var buildPdf = function(error){
    var pdfLetter;

    var child = exec('wkhtmltopdf temp.html compensation.pdf', function(error, stdout, stderr) {
        if (error)
            res.send({
                err:error.message
                });
        else
            res.send({
                output : stdout.toString()
        });
                    // sendEmail();
    });
};

You've encountered a wkhtmltopdf gotcha. It doesn't write status information to STDOUT, it writes it to STDERR.

$ node -e \
  "require('child_process').exec( \
   'wkhtmltopdf http://stackoverflow.com/ foo.pdf', \
   function(err, stdout, stderr) { process.stdout.write( stderr ); } );"
Loading pages (1/6)
content-type missing in HTTP POST, defaulting to application/octet-stream
Counting pages (2/6)
Resolving links (4/6)
Loading headers and footers (5/6)
Printing pages (6/6)
Done

I've just finished getting this to work via Node.js on Heroku and wanted to post since I had to get over a couple of tiny hurdles.

// Spin up a new child_process to handle wkhtmltopdf.
var spawn = require('child_process').spawn;

// stdin/stdout, but see below for writing to tmp storage.
wkhtmltopdf = spawn('./path/to/wkhtmltopdf', ['-', '-']);

// Capture stdout (the generated PDF contents) and append it to the response.
wkhtmltopdf.stdout.on('data', function (data) {
    res.write(data);
});

// On process exit, determine proper response depending on the code.
wkhtmltopdf.on('close', function (code) {
    if (code === 0) {
        res.end();
    } else {
        res.status(500).send('Super helpful explanation.');
    }
});

res.header('Content-Type', 'application/octet-stream');
res.header('Content-Disposition', 'attachment; filename=some_file.pdf');
res.header('Expires', '0');
res.header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');

// Write some markup to wkhtmltopdf and then end the process. The .on 
// event above will be triggered and the response will get sent to the user.
wkhtmltopdf.stdin.write(some_markup);
wkhtmltopdf.stdin.end();

On the Cedar-14 stack at Heroku, I couldn't get wkhtmltopdf to write to stdout. The server always responded with Unable to write to destination. The trick there was to write to ./.tmp and then stream the written file back out to the user – easy enough:

wkhtmltopdf = spawn('./path/to/wkhtmltopdf', ['-', './.tmp/some_file.pdf']);

wkhtmltopdf.on('close', function (code) {
    if (code === 0) {

        // Stream the file.
        fs.readFile('./.tmp/some_file.pdf', function(err, data) {

            res.header('Content-Type', 'application/octet-stream');
            res.header('Content-Disposition', 'attachment; filename=' + filename);
            res.header('Expires', '0');
            res.header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');

            res.send(data);
        });
    } else {
        res.status(500).send('Super helpful explanation.');
    }
});

res.header('Content-Type', 'application/octet-stream');
res.header('Content-Disposition', 'attachment; filename=' + filename);
res.header('Expires', '0');
res.header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');