<commit_before>'use strict';

/**
 * Module dependencies.
 */

require('should');

var async = require('async');
var path = require('path');
var spawn = require('child_process').spawn;
var temp = require('temp').track();

var consul = require('../lib');

/**
 * Cluster
 */

function Cluster() {
  this._started = false;
  this.process = {};
}

Cluster.prototype.spawn = function(options, callback) {
  var self = this;

  var binPath = process.env.CONSUL_BIN || 'consul';

  var args = ['agent'];

  Object.keys(options).forEach(function(key) {
    args.push('-' + key);

    if (options.hasOwnProperty(key) && typeof options[key] !== 'boolean' &&
        options[key] !== undefined) {
      args.push('' + options[key]);
    }
  });

  var jobs = {};

  jobs.dirPath = function(cb) {
    temp.mkdir({}, cb);
  };

  jobs.process = ['dirPath', function(cb, results) {
    args.push('-data-dir');
    args.push(path.join(results.dirPath, options.node, 'data'));

    args.push('-pid-file');
    args.push(path.join(results.dirPath, options.node, 'pid'));

    var process = spawn(binPath, args);

    process.destroy = function() {
      process._destroyed = true;
      process.kill('SIGKILL');
    };

    self.process[options.node] = process;

    var out = '';
    process.stdout.on('data', function(data) { out += data.toString(); });
    process.stderr.on('data', function(data) { out += data.toString(); });

    process.on('exit', function(code) {
      if (code !== 0 && !process._destroyed) {
        var err = new Error('Server existed (' + options.node + ')\n');
        err.message += 'Command: ' + binPath + ' ' + JSON.stringify(args) + '\n';
        err.message += 'Output:\n' + out;
        throw err;
      }
    });

    cb(null, process);
  }];

  jobs.connected = ['process', function(cb, results) {
    var started = false;
    var count = 0;

    var client = consul({ host: options.bind });

    async.until(
      function() { return started || count > 1000; },
      function(cb) {
        count++;

        // wait until server starts
        if (options.bootstrap) {
          client.kv.set('check', 'ok', function(err) {
            if (err) return setTimeout(function() { cb(); }, 10);

            started = true;

            cb();
          });
        } else {
          client.agent.self(function(err) {
            if (err) return setTimeout(function() { cb(); }, 10);

            started = true;

            cb();
          });
        }
      },
      function(err) {
        if (err || !started) {
          results.process.destroy();

          return cb(new Error('Failed to start: ' + options.node));
        }

        cb();
      }
    );
  }];

  async.auto(jobs, callback);
};

Cluster.prototype.setup = function(callback) {
  var self = this;

  if (self._started) return callback(new Error('already started'));
  self._started = true;

  var jobs = {};
<commit_msg>Use retry in helper<commit_after>'use strict';

/**
 * Module dependencies.
 */

require('should');

var async = require('async');
var path = require('path');
var spawn = require('child_process').spawn;
var temp = require('temp').track();

var consul = require('../lib');

/**
 * Cluster
 */

function Cluster() {
  this._started = false;
  this.process = {};
}

Cluster.prototype.spawn = function(options, callback) {
  var self = this;

  var binPath = process.env.CONSUL_BIN || 'consul';

  var args = ['agent'];

  Object.keys(options).forEach(function(key) {
    args.push('-' + key);

    if (options.hasOwnProperty(key) && typeof options[key] !== 'boolean' &&
        options[key] !== undefined) {
      args.push('' + options[key]);
    }
  });

  var jobs = {};

  jobs.dirPath = function(cb) {
    temp.mkdir({}, cb);
  };

  jobs.process = ['dirPath', function(cb, results) {
    args.push('-data-dir');
    args.push(path.join(results.dirPath, options.node, 'data'));

    args.push('-pid-file');
    args.push(path.join(results.dirPath, options.node, 'pid'));

    var process = spawn(binPath, args);

    process.destroy = function() {
      process._destroyed = true;
      process.kill('SIGKILL');
    };

    self.process[options.node] = process;

    var out = '';
    process.stdout.on('data', function(data) { out += data.toString(); });
    process.stderr.on('data', function(data) { out += data.toString(); });

    process.on('exit', function(code) {
      if (code !== 0 && !process._destroyed) {
        var err = new Error('Server existed (' + options.node + ')\n');
        err.message += 'Command: ' + binPath + ' ' + JSON.stringify(args) + '\n';
        err.message += 'Output:\n' + out;
        throw err;
      }
    });

    cb(null, process);
  }];

  jobs.connected = ['process', function(cb, results) {
    var client = consul({ host: options.bind });

    async.retry(
      100,
      function(cb) {
        // wait until server starts
        if (options.bootstrap) {
          client.kv.set('check', 'ok', function(err) {
            if (err) return setTimeout(function() { cb(err); }, 100);
            cb();
          });
        } else {
          client.agent.self(function(err) {
            if (err) return setTimeout(function() { cb(err); }, 100);
            cb();
          });
        }
      },
      function(err) {
        if (err) {
          results.process.destroy();

          return cb(new Error('Failed to start: ' + options.node));
        }

        cb();
      }
    );
  }];

  async.auto(jobs, callback);
};

Cluster.prototype.setup = function(callback) {
  var self = this;

  if (self._started) return callback(new Error('already started'));
  self._started = true;

  var jobs = {};

{'fraction_non_alphanumeric': 0.1839689265536723, 'fraction_numerical': 0.0035310734463276836, 'mean_word_length': 2.44796104686549, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5166648', 'n_tokens_mistral': 1816, 'n_tokens_neox': 1736, 'n_words': 379}