Meteor method return after createWriteStream finished?


#1

I would like to have a Meteor method return true after a NodeJS script with createWriteStream has finished. However, currently it returns as soon as the createWriteStream starts. How can I get it to wait?

Here’s the code I have currently:

const fs   = require( 'fs' );
const path = require( 'path' );

Meteor.methods({
  importCSVServer( doc ) {
    const urlObj        = doc.importURL;

    try {
      let thisKey     = urlObj.key.slice(1),
          getS3params = {
                            Bucket: '<bucket_name>',
                            Key: thisKey
                          },
          // Build a path string to the local CSV
          csvFile     = importDir + urlObj.name,
          // Create a write stream for data to land when coming from S3
          writeFile   = fs.createWriteStream( csvFile ),
          // Stream data from the CSV on S3 and pipe it to a new CSV on the server
          getFile     = S3.aws.getObject( getS3params ).createReadStream().pipe( writeFile );

      // Watch for events on the write stream. When finished writing from S3, start processing
      writeFile.
        on( 'error', ( error ) => {
          console.warn( 'writeFile error:' );
          console.warn( error );
        }).
        on( 'finish', Meteor.bindEnvironment( ( error, response ) => {
          Baby.parseFiles( csvFile, {
            header: true,
            step: ( results, parser ) => {
              <process csv row here>
            }, // End step function
            complete: ( results, file ) => {
              console.log( 'import finished' + ' at ' + moment().format() );

              let deleteFile = fs.unlinkSync( csvFile );

              return 'completed';
            }
          }); // end Baby.parseFiles
        })); // end on.Finish
    } catch ( error ) {
      console.warn('import error' );
      console.warn( error );
      throw new Meteor.Error( 500, 'Import failed.' );
    }
  }
});

I have tried moving the writeStream workflow to a separate function and have also looked at Meteor.wrapAsync and Futures, but writeStream always seems to destroy the order.

Appreciate any suggestions you may have.


#2

Because meteor methods run synchronously. You have to ‘halt’ the return value until your result comes back as it were. This is a package that helps with that: https://atmospherejs.com/meteorhacks/async

In this case you could use

var asyncReturn = Async.runSync(function(done){
    ..... // All your async code in here
    .on('finish', (error, response) => {
        done(null, 'completed');
    });
});

return asyncReturn .result;

If you’re interested just read up on fibers, but this should help.


#3

Thanks @nlammertyn! That helped.