-2

I have a simple web app that is logging onto my customer facing webservers and downloading the log files on a get request. When you send a get request to a certain route a module initiates that connects via sftp to the webserver and downloads the logs locally, for 2 separate servers. For some reason the last then() method in my chain is getting triggered before the promise resolves.

router.js:

var express = require('express');
var router = express.Router();
var gather = require('../api/gather');
/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('home');
});
router.get('/api/gather',function(req,res,next){
  console.log('sending web9 target');
  gather.logs(['WEB9'])
    .then((logsFound)=>{
      console.log('sending web 11 target');
      gather.logs(['WEB11',logsFound])
  })
  .then((logsFound)=>{
    console.log(logsFound);
    console.log('downloading finished rendering home with message');
    res.render('home',{message: logsFound+' Log Files Ready for Pickup'});
  })  
  .catch((e)=>{
    res.render('home',{message: e});  
  });

});
module.exports = router;

/api/gather.js

//require ftp modules and define client
let Client = require('ssh2-sftp-client');
let sftp = new Client();
var fs = require('fs');
let sftp2 = new Client();
//set server configs
var boomeConfig = {
    host: process.env.FTP_HOST,
    port: process.env.FTP_PORT,
    username: process.env.FTP_USER,
    password: process.env.FTP_PASS
};
var webServerConfig = {
    port: process.env.WEB_PORT,
    username: process.env.WEB_USER,
    password: process.env.WEB_PASS
};
let message;
const logDir = '/opt/foobar/logs/';
module.exports.logs = function(req, res){
    console.log('hit gather module');
    const target = req[0];
    let logsFound = req[1] || 0;
    return new Promise((resolve,reject)=>{
            if(target === 'WEB9'){
                webServerConfig.host = process.env.WEB9_HOST;
            }else if(target === 'WEB11'){
                webServerConfig.host = process.env.WEB11_HOST;    
            }else{
                message = 'No Server Target Found';
                resolve(message);
            }    
            sftp.connect(webServerConfig)
            .then(()=>{
                return sftp.list(logDir);
            })
            .then((data)=>{
                for(var i = 0; i < data.length; i++){
                    const remoteFileName = logDir + data[i].name;
                    const localFileName = './downloads/'+target+'/' + data[i].name;
                    //console.log('saving file '+localFileName);
                    sftp.get(remoteFileName).then((stream) => {
                        stream.pipe(fs.createWriteStream(localFileName));
                    });
                }
                console.log('Found '+data.length+' Logs on '+target);
                sftp.end();
                logsFound += data.length;
                console.log('Got '+target+' Files Moving to next');
                if(target ==='WEB11'){
                    console.log('Total count '+logsFound);
                }
            }).then((logsFound)=>{
                resolve(logsFound);
            })
            .catch((e)=>{
                console.log('error: '+e);
                reject(e);    
            });
    })    
}

my home route is getting rendered with logsFound as undefined.

The only thing I can think of is that its possible the

sftp.get(remoteFileName).then((stream) => {
                        stream.pipe(fs.createWriteStream(localFileName));
                    });

is still streaming files when the promise resolves.

Oluwafemi Sule
  • 36,144
  • 1
  • 56
  • 81
Jay Lane
  • 1,379
  • 15
  • 28
  • Is "sending web 11 target" is logging in route file? – Prakash Sharma Jul 25 '17 at 19:46
  • yes but its happening after 'downloading finished rendering home with message' console.log – Jay Lane Jul 25 '17 at 19:48
  • 1
    you didn't give it something to wait on. in several places. If you don't return a promise from .then(), it will just keep going. – Kevin B Jul 25 '17 at 20:18
  • Also, avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Jul 25 '17 at 20:42

1 Answers1

0

Issue was I was resolving my promises but the way my route was written I was creating the Promise constructor antipattern. Thanks to Bergi and Kevin B.

edited route

    var express = require('express');
    var router = express.Router();
    var gather = require('../api/gather');
    /* GET home page. */
    router.get('/', function(req, res, next) {
      res.render('home');
    });
    router.get('/api/gather',function(req,res,next){
      console.log('sending web9 target');
      return gather.logs(['WEB9'])
        .then((logsFound)=>{
          console.log('sending web 11 target');
          return gather.logs(['WEB11',logsFound])
      })
      .then((logsFound)=>{
        console.log(logsFound);
        console.log('downloading finished rendering home with message');
        res.render('home',{message: logsFound+' Log Files Ready for Pickup'});
      })  
      .catch((e)=>{
        res.render('home',{message: e});  
      });

    });
    module.exports = router;
Jay Lane
  • 1,379
  • 15
  • 28