UNPKG

2.93 kBJavaScriptView Raw
1var through = require('through2').obj;
2var request = require('request-promise');
3var Promise = require('bluebird');
4
5function wait(ms) {
6 return new Promise(function(resolve){
7 setTimeout(resolve, ms);
8 });
9}
10
11function client(baseUrl, options){
12 var queue = [],
13 ended = false,
14 ending = false,
15 retries = 0,
16 errorCount = 0,
17 id, req, task;
18
19 function send() {
20 if (!queue.length && (!ending || ended)) {
21 return Promise.resolve();
22 }
23 if (req) {
24 return req;
25 }
26
27 var commands = queue;
28 queue = [];
29
30 if (ending) {
31 ended = true;
32 }
33
34 var url;
35
36 if (id) {
37 url = '/tasks/'+id;
38 } else {
39 url = '/tasks';
40 }
41
42 var end = ending;
43
44 var post = {
45 url: baseUrl+url,
46 json: true,
47 body: {
48 commands: commands,
49 end: end
50 }
51 };
52 for (var key in options) {
53 post.body[key] = options[key];
54 }
55
56 req = (
57 request.post(post).then(function(body){
58 task = body;
59 id = task.id;
60 ended = end;
61 req = null;
62
63 var self = this;
64
65 task.errors.slice(0, errorCount)
66 .forEach(function(err){
67 self.emit('error', err);
68 });
69
70 errorCount += task.errors.length;
71
72 send();
73 return;
74 }).catch(function(err){
75 queue = commands.concat(queue);
76 req = null;
77
78 retries++;
79 if (retries === 10) {
80 console.log('Failed to run commands after 10 retries\n '+commands.join('\n '), err);
81 throw err;
82 }
83
84 return wait(1000 * 10).then(send);
85 })
86 );
87
88 return req;
89 }
90
91 function end() {
92 ending = true;
93 return send();
94 }
95
96 var pollRetries = 0, polls = 0;
97
98 function pollForCompletion(delayed) {
99 if (delayed) {
100 return (new Promise(function(resolve){
101
102 var delay = 4096;
103 if (polls <= 11) {
104 delay = 10+Math.pow(2, polls); //EXPONENTIAL BACKOFF YAY
105 }
106 polls++;
107
108 setTimeout(resolve, delay);
109 }).then(pollForCompletion));
110 }
111
112 return (
113 request.get({
114 url: baseUrl+'/tasks/'+id,
115 json: true
116 }).then(function(body){
117 task = body;
118 if (task.running) {
119 return pollForCompletion(true);
120 } else {
121 return task;
122 }
123 })
124 .catch(function(err){
125 pollRetries++;
126
127 if (pollRetries === 10) {
128 throw err;
129 }
130
131 return pollForCompletion(true);
132 })
133 );
134 }
135
136 return through(function(command, enc, cb){
137 queue.push(command);
138 send().then(cb.bind(null, null, null)).catch(cb);
139 }, function(cb){
140 var self = this;
141 end()
142 .then(pollForCompletion)
143 .then(function(){
144 self.push(task);
145 cb();
146 })
147 .catch(cb);
148 });
149}
150
151module.exports = client;