Skip to content

Commit a1cd963

Browse files
authored
[AZI-529] improve log forwarder retry behavior (#596)
* [AZI-529] add retry with delay * [AZI-529] skip retrying 4xx responses * [AZI-529] fix status code retry * [AZI_529] change retry timeout
1 parent 1f32451 commit a1cd963

File tree

1 file changed

+58
-39
lines changed

1 file changed

+58
-39
lines changed

azure/activity_logs_monitoring/index.js

Lines changed: 58 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
var https = require('https');
77

8-
const VERSION = '0.5.6';
8+
const VERSION = '0.5.7';
99

1010
const STRING = 'string'; // example: 'some message'
1111
const STRING_ARRAY = 'string-array'; // example: ['one message', 'two message', ...]
@@ -29,6 +29,9 @@ const DD_SERVICE = process.env.DD_SERVICE || 'azure';
2929
const DD_SOURCE = process.env.DD_SOURCE || 'azure';
3030
const DD_SOURCE_CATEGORY = process.env.DD_SOURCE_CATEGORY || 'azure';
3131

32+
const MAX_RETRIES = 4; // max number of times to retry a single http request
33+
const RETRY_INTERVAL = 250; // amount of time (milliseconds) to wait before retrying request, doubles after every retry
34+
3235
/*
3336
To scrub PII from your logs, uncomment the applicable configs below. If you'd like to scrub more than just
3437
emails and IP addresses, add your own config to this map in the format
@@ -155,52 +158,70 @@ class HTTPClient {
155158
var batches = this.batcher.batch(records);
156159
var promises = [];
157160
for (var i = 0; i < batches.length; i++) {
158-
promises.push(this.sendWithRetry(batches[i]));
161+
promises.push(this.send(batches[i]));
159162
}
160163
return await Promise.all(
161164
promises.map(p => p.catch(e => this.context.log.error(e)))
162165
);
163166
}
164167

165-
sendWithRetry(record) {
166-
return new Promise((resolve, reject) => {
167-
return this.send(record)
168-
.then(res => {
169-
resolve(true);
170-
})
171-
.catch(err => {
172-
this.send(record)
173-
.then(res => {
174-
resolve(true);
175-
})
176-
.catch(err => {
177-
reject(
178-
`unable to send request after 2 tries, err: ${err}`
179-
);
180-
});
181-
});
182-
});
168+
isStatusCodeValid(statusCode) {
169+
return statusCode >= 200 && statusCode <= 299;
170+
}
171+
172+
shouldStatusCodeRetry(statusCode) {
173+
// don't retry 4xx responses
174+
return (
175+
!this.isStatusCodeValid(statusCode) &&
176+
(statusCode < 400 || statusCode > 499)
177+
);
183178
}
184179

185180
send(record) {
181+
var numRetries = MAX_RETRIES;
182+
var retryInterval = RETRY_INTERVAL;
186183
return new Promise((resolve, reject) => {
187-
const req = https
188-
.request(this.httpOptions, resp => {
189-
if (resp.statusCode < 200 || resp.statusCode > 299) {
190-
reject(`invalid status code ${resp.statusCode}`);
191-
} else {
192-
resolve(true);
184+
const sendRequest = (options, record) => {
185+
const retryRequest = errMsg => {
186+
if (numRetries === 0) {
187+
return reject(errMsg);
193188
}
194-
})
195-
.on('error', error => {
196-
reject(error);
197-
});
198-
req.on('timeout', () => {
199-
req.destroy();
200-
reject(`request timed out after ${DD_REQUEST_TIMEOUT_MS}ms`);
201-
})
202-
req.write(this.scrubber.scrub(JSON.stringify(record)));
203-
req.end();
189+
this.context.log.warn(
190+
`Unable to send request, with error: ${errMsg}. Retrying ${numRetries} more times`
191+
);
192+
numRetries--;
193+
retryInterval *= 2;
194+
setTimeout(() => {
195+
sendRequest(options, record);
196+
}, retryInterval);
197+
};
198+
const req = https
199+
.request(options, resp => {
200+
if (this.isStatusCodeValid(resp.statusCode)) {
201+
resolve(true);
202+
} else if (
203+
this.shouldStatusCodeRetry(resp.statusCode)
204+
) {
205+
retryRequest(
206+
`invalid status code ${resp.statusCode}`
207+
);
208+
} else {
209+
reject(`invalid status code ${resp.statusCode}`);
210+
}
211+
})
212+
.on('error', error => {
213+
retryRequest(error.message);
214+
})
215+
.on('timeout', () => {
216+
req.destroy();
217+
retryRequest(
218+
`request timed out after ${DD_REQUEST_TIMEOUT_MS}ms`
219+
);
220+
});
221+
req.write(this.scrubber.scrub(JSON.stringify(record)));
222+
req.end();
223+
};
224+
sendRequest(this.httpOptions, record);
204225
});
205226
}
206227
}
@@ -219,9 +240,7 @@ class Scrubber {
219240
);
220241
} catch {
221242
context.log.error(
222-
`Regexp for rule ${name} pattern ${
223-
settings['pattern']
224-
} is malformed, skipping. Please update the pattern for this rule to be applied.`
243+
`Regexp for rule ${name} pattern ${settings['pattern']} is malformed, skipping. Please update the pattern for this rule to be applied.`
225244
);
226245
}
227246
}

0 commit comments

Comments
 (0)