UNPKG

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