New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

serviced

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

serviced - npm Package Compare versions

Comparing version 1.0.2 to 2.0.0

8

package.json
{
"name": "serviced",
"version": "1.0.2",
"version": "2.0.0",
"description": "Microservice dependency readiness probe",

@@ -10,3 +10,3 @@ "main": "serviced.js",

"scripts": {
"start": "DEBUG=$npm_package_name nodemon -q --exec 'node test.js | tap -R silent -'",
"start": "DEBUG=$npm_package_name* nodemon -q --exec 'node test.js | tap -R spec -'",
"test": "tap -R spec test.js",

@@ -34,4 +34,4 @@ "linter": "eslint .",

"dependencies": {
"backoff": "^2.5.0",
"request": "^2.72.0"
"request": "^2.72.0",
"retry": "^0.9.0"
},

@@ -38,0 +38,0 @@ "devDependencies": {

const debug = require('debug')('serviced');
const backoff = require('backoff');
const retry = require('retry');
const request = require('request');
const defaults = {
method: 'GET',
json: true,
randomisationFactor: 0, // must be between 0 and 1
initialDelay: 100,
maxDelay: 10000,
numberOfBackoffs: null,
error: null,
pings: [],
test() {
return true;
url: null,
request: {
json: true,
},
retry: {
retries: 2,
maxTimeout: 2 * 1000,
},
test: null,
failure: null,
};
function Services(...services) {
debug('Setting up probes for %o services.', services.length);
function Service(svc) {
debug('Instantiating service with: %o', svc);
const promises = services.map((options, i) => {
const promise = new Promise((resolve, reject) => {
debug('Setting up probe for %o', (options.name || i));
const service = Object.assign({}, defaults, options);
const service = (typeof svc === 'string') ? { url: svc } : svc;
const options = Object.assign({}, defaults, service);
const ping = backoff.exponential(service);
debug('Setting url in request options.');
options.request.uri = options.url;
ping.on('backoff', (count, delay) => {
service.pings.push({ count, delay });
});
return new Promise((resolve, reject) => {
debug('Instantiating retry with: %o', options.retry);
const operation = retry.operation(options.retry);
operation.attempt(attempt => {
let error = null;
debug('Attempt: %o', attempt);
debug('Creating request with: %o', options.request);
request(options.request, (err, res, body) => {
debug('Operation error: %o', operation.mainError());
debug('Operation errors: %o', operation.errors());
// operation.retry(true);
if (err) {
debug('Retrying - HTTP error: %o', err);
error = err;
} else {
if (typeof options.test !== 'function') {
debug('No test supplied.');
debug('Checking status code: %o', res.statusCode);
if (res.statusCode !== 200) {
debug('Status code check failed. Code: %o', res.statusCode);
error = new Error('Status code is not 200.');
}
} else {
debug('Test supplied.');
debug('Tesing response body: %o', body);
if (options.test(body) !== true) {
debug('Supplied test failed.');
error = new Error('Serviced test failed.');
}
}
}
if (service.numberOfBackoffs !== null) {
ping.failAfter(service.numberOfBackoffs);
}
ping.on('ready', (count, delay) => {
debug('Probing: %o', options.url);
service.delay = delay;
request(options, (err, res, body) => {
service.error = err;
if (err !== null) {
debug('Probe HTTP error: %o', err);
ping.backoff();
} else if (service.test(body) !== true) {
debug('Probe test failed.');
ping.backoff();
if (error !== null) {
debug('Error found.');
if (attempt < options.retry.retries) {
debug('Additional retries available.');
operation.retry(error);
} else {
resolve(service);
debug('No additional retries available.');
debug('Rejecting promise.');
debug('Main Error: %o', operation.mainError());
debug('All Errors: %o', operation.errors());
reject(operation.mainError());
}
});
});
ping.on('fail', () => {
if (!service.error) {
service.error = 'PINGTIMEOUT';
} else {
debug('Resolving promise.');
resolve();
}
const info = {
error: service.error,
pings: service.pings,
};
debug('Failed to reach service: %o', info);
reject(info);
});
ping.backoff();
});
return promise;
});
}
return Promise.all(promises);
function Services(...services) {
debug('Instantiating services');
return Promise.all(services.map(service => new Service(service)));
}
module.exports = Services;

@@ -0,70 +1,98 @@

const debug = require('debug')('serviced:test');
const http = require('http');
const tap = require('tap');
const Serviced = require('.');
const passingService1 = {
name: 'db',
url: 'http://localhost:3000',
method: 'GET',
json: true,
maxDelay: 3000,
numberOfBackoffs: 3,
test(body) {
return body.here === true;
},
};
function Server(output = {}, cb = () => {}) {
debug('Creating test server');
debug('Set output: %o', output);
const server = http.createServer((request, response) => {
response.writeHead(200, { 'Content-Type': 'application/json' });
response.end(JSON.stringify(output));
});
server.listen(0, 'localhost', () => {
const endpoint = `http://localhost:${server.address().port}`;
debug('Server ready at: %o', endpoint);
cb(endpoint);
});
return server;
}
const faillingService1 = {
name: 'db',
url: 'http://localhost:3000',
method: 'GET',
json: true,
maxDelay: 3000,
numberOfBackoffs: 3,
test(body) {
return body.heres === true;
},
};
tap.test('Single working service with string option.', t => {
const server = new Server({ foo: 'bar' }, (endpoint) => {
new Serviced(endpoint).then(() => {
t.end();
server.close();
});
});
});
const passingService2 = {
name: 'kube',
url: 'http://localhost:3000',
method: 'GET',
json: true,
maxDelay: 300,
numberOfBackoffs: 10,
test(body) {
return body.here === true;
},
};
tap.test('Single working service with object options.', t => {
const server = new Server({ foo: 'bar' }, (endpoint) => {
new Serviced({ url: endpoint }).then(() => {
t.end();
server.close();
});
});
});
const faillingService2 = {
name: 'kube',
url: 'http://localhost:3000',
method: 'GET',
json: true,
maxDelay: 300,
numberOfBackoffs: 10,
test(body) {
return body.heres === true;
},
};
tap.test('Single working service with passing test.', t => {
const server = new Server({ foo: 'bar' }, (endpoint) => {
new Serviced({
url: endpoint,
test(body) {
return body.foo === 'bar';
},
}).then(() => {
t.end();
server.close();
});
});
});
tap.test('Single working service probe.', t => {
const services = new Serviced(passingService1);
services.then(() => t.end());
tap.test('Single working service with FAILING test.', t => {
const server = new Server({ foo: 'bar' }, (endpoint) => {
new Serviced({
url: endpoint,
test(body) {
return body.foo === 'foo';
},
}).catch(() => {
t.end();
server.close();
});
});
});
tap.test('Single FAILLING service probe.', t => {
const services = new Serviced(faillingService1);
services.catch(() => t.end());
tap.test('Single unreachable service.', t => {
new Serviced('http://fakehost').catch(() => {
t.end();
});
});
tap.test('Multiple working services probes.', t => {
const services = new Serviced(passingService1, passingService2);
services.then(() => t.end());
tap.test('Multiple working services.', t => {
const server1 = new Server({ foo: 'bar' }, (endpoint1) => {
const server2 = new Server({ bar: 'foo' }, (endpoint2) => {
new Serviced(endpoint1, endpoint2).then(() => {
t.end();
server1.close();
server2.close();
});
});
});
});
tap.test('Multiple FAILLING services probes.', t => {
const services = new Serviced(faillingService1, faillingService2);
services.catch(() => t.end());
tap.test('Multiple unreachable services.', t => {
new Serviced('http://fakehost', 'http://fakehost2').catch(() => {
t.end();
});
});
tap.test('Multiple mixed availability services.', t => {
const server = new Server({ foo: 'bar' }, (endpoint) => {
new Serviced(endpoint, 'http://fakehost2').catch(() => {
t.end();
server.close();
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc