Why does my server never receive any requests made inside of a loop in Node.js?

My code works fine outside of a loop:

var localFolder = '/home/transcripts',
    apiHost = 'https://someserver'
    apiCall = '/path',
    sharedSecret = 'secret';
/* includes */

var sys = require('sys'),
    fs = require('fs'),
    exec = require('child_process').exec,
    querystring = require('querystring'),
    crypto = require('crypto')
    request = require('request');
var file = "index_07_03_2013_1209576.csv";

console.log('Pushing CSV to API: ' + file);
var r = request.post(
    apiHost + '/' + apiCall,
    {   form: {
            'filename': file,
            'accessToken': crypto.createHash('md5').update(file + sharedSecret).digest('hex')
        }
    },
    function (error, response, body) {
        if (!error && response.statusCode == 200) {
            console.log(body);
        }
        console.log(error);
        console.log(response);
    }
);

file = "index_07_02_2013_1548773.csv";

console.log('Pushing CSV to API: ' + file);
var r = request.post(
    apiHost + '/' + apiCall,
    {   form: {
            'filename': file,
            'accessToken': crypto.createHash('md5').update(file + sharedSecret).digest('hex')
        }
    },
    function (error, response, body) {
        if (!error && response.statusCode == 200) {
            console.log(body);
        }
        console.log(error);
        console.log(response);
    }
);

file = "index_07_02_2013_1548773.csv";

console.log('Pushing CSV to API: ' + file);
var r = request.post(
    apiHost + '/' + apiCall,
    {   form: {
            'filename': file,
            'accessToken': crypto.createHash('md5').update(file + sharedSecret).digest('hex')
        }
    },
    function (error, response, body) {
        if (!error && response.statusCode == 200) {
            console.log(body);
        }
        console.log(error);
        console.log(response);
    }
);

However, when I try to move it into a forEach loop, no request is ever received by the server. I do see output indicating that the CSV file is being pushed to the API, but the request never seems to hit the server. Here's the code for that:

#!/usr/local/bin/node

/* environment vars */

var localFolder = '/home/transcripts',
    apiHost = 'https://someserver'
    apiCall = '/path',
    sharedSecret = 'secret';

/* includes */

var sys = require('sys'),
    fs = require('fs'),
    exec = require('child_process').exec,
    querystring = require('querystring'),
    crypto = require('crypto')
    request = require('request');

var counter = 0;

fs.readdir(localFolder, function(err, files) {

    files.forEach(function(file) {

        if (file.substr(-3, 3) == 'csv') {


            console.log('Pushing CSV to API: ' + file);
            request.post(
                apiHost + '/' + apiCall,
                {   form: {
                        'filename': file,
                        'accessToken': crypto.createHash('md5').update(file + sharedSecret).digest('hex')
                    }
                },
                function (error, response, body) {
                    if (!error && response.statusCode == 200) {
                        console.log(body);
                    }
                    console.log(error);
                    console.log(response);
                }
            );
            console.log(request);

        }

        counter++;

    });

    if (counter >= files.length) {

        process.exit(0);

    }

});

Anyone have any ideas what the problem might be?

I guess the looping version breaks because you run process.exit(0) as soon as counter >= files.length evaluates to true.

The reason it actually breaks the intended functionality is probably because you spin off the request calls (which are asynchronous) very fast, and once you've done that, you exit the program. My guess is that since you don't actually wait for the requests to finish (i.e. when the callbacks are done), you exit the program prematurely.

What you need is basically a wait group, and that you make sure not to exit your program before all the callbacks are done.

Try something like this:

// imports, etc
// ...

var counter = 0;

function done() {
  counter--;

  if(counter === 0) {
    process.exit(0);
  }
}

var callback = function (error, response, body) {
  if (!error && response.statusCode == 200) {
    console.log(body);
  }
  console.log(error);
  console.log(response);

  done();
}


fs.readdir(localFolder, function(err, files) {
  counter = files.length;

  files.forEach(function(file) {
    if (file.substr(-3, 3) == 'csv') {
      console.log('Pushing CSV to API: ' + file);
      var data = { 
        form: {
          'filename': file,
          'accessToken': crypto.createHash('md5').update(file + sharedSecret).digest('hex')
        }
      }

      request.post(apiHost + '/' + apiCall, , data, callback);
    }
  }
);