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

dns-endpoint-pool

Package Overview
Dependencies
Maintainers
2
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dns-endpoint-pool - npm Package Compare versions

Comparing version 1.2.0 to 1.3.0

4

CHANGELOG.md

@@ -0,3 +1,7 @@

## 1.3.0 / 2017-05-30
- Adds a new circuit breaker algorithm which is less reliant on traffic rates.
## 1.2.0 / 2017-05-29
- Add `getStatus()` method.

15

index.js

@@ -1,9 +0,9 @@

var EndpointPool,
_ = require('underscore'),
dns = require('dns'),
Events = require('events'),
PoolManager = require('./pool-manager'),
util = require('util'),
var EndpointPool;
var _ = require('underscore');
var dns = require('dns');
var Events = require('events');
var PoolManager = require('./pool-manager');
var util = require('util');
DNS_LOOKUP_TIMEOUT = 1000;
var DNS_LOOKUP_TIMEOUT = 1000;

@@ -88,3 +88,2 @@ /**

var poolStatus = this.poolManager.getStatus();
var endpoints = this.poolManager.endpoints;
return _.assign({

@@ -91,0 +90,0 @@ age: Date.now() - this.lastUpdate

{
"name": "dns-endpoint-pool",
"version": "1.2.0",
"version": "1.3.0",
"description": "Manage and load-balance a pool of service endpoints retrieved from a DNS lookup for a service discovery name.",

@@ -5,0 +5,0 @@ "main": "index.js",

var _ = require('underscore');
// endpoint states
var CLOSED = 0; // closed circuit: endpoint is good to use
var HALF_OPEN_READY = 1; // endpoint is in recovery state: offer it for use once
var HALF_OPEN_PENDING = 2; // endpoint recovery is in process
var OPEN = 3; // open circuit: endpoint is no good

@@ -20,3 +25,6 @@ function PoolManager (options) {

getNextEndpoint: function () {
var i, l, offset, endpoint;
var i;
var l;
var offset;
var endpoint;

@@ -35,3 +43,4 @@ for (i = 0, l = this.endpoints.length; i < l; ++i) {

updateEndpoints: function (endpoints) {
var matchingEndpoint, i;
var matchingEndpoint;
var i;
var newEndpoints = endpoints.map(function (info) {

@@ -65,3 +74,3 @@ return new Endpoint(info);

}, 0)
}
};
}

@@ -81,17 +90,21 @@ };

ejectOnErrorPoolManager: function (options) {
// endpoint states
var CLOSED = 0, // closed circuit: endpoint is good to use
HALF_OPEN_READY = 1, // endpoint is in recovery state: offer it for use once
HALF_OPEN_PENDING = 2, // endpoint recovery is in process
OPEN = 3; // open circuit: endpoint is no good
if (!options) {
throw new Error('Must supply arguments to ejectOnErrorPoolManager');
}
if (!options || !(options.failureWindow && options.maxFailures && options.resetTimeout)) {
throw new Error('Must supply all arguments to ejectOnErrorPoolManager');
var poolConfig;
if (options.failureWindow && options.maxFailures && options.resetTimeout) {
poolConfig = getRollingWindowConfiguration(options.failureWindow, options.maxFailures, options.resetTimeout);
} else if (options.failureRate && options.failureRateWindow && options.resetTimeout) {
poolConfig = getRateConfiguration(options.failureRate, options.failureRateWindow, options.resetTimeout);
} else {
throw new Error('Must supply either configuration to ejectOnErrorPoolManager');
}
var failureWindow = options.failureWindow;
var maxFailures = options.maxFailures;
var resetTimeout = options.resetTimeout;
return new PoolManager(poolConfig);
function disableEndpoint(endpoint) {
if (endpoint.state === OPEN) {
return;
}
endpoint.state = OPEN;

@@ -101,55 +114,89 @@ clearInterval(endpoint._reopenTimeout);

endpoint.state = HALF_OPEN_READY;
}, resetTimeout);
}, options.resetTimeout);
}
function isInPool(endpoint) {
return endpoint.state === CLOSED || endpoint.state === HALF_OPEN_READY;
}
function onEndpointSelected(endpoint) {
if (endpoint.state === HALF_OPEN_READY) {
endpoint.state = HALF_OPEN_PENDING; // let one through, then turn it off again
}
}
return new PoolManager({
isInPool: function (endpoint) {
switch (endpoint.state) {
case HALF_OPEN_READY:
case CLOSED:
return true;
default:
return false;
}
},
onEndpointSelected: function (endpoint) {
if (endpoint.state === HALF_OPEN_READY) {
endpoint.state = HALF_OPEN_PENDING; // let one through, then turn it off again
}
},
onEndpointRegistered: function (endpoint) {
endpoint.state = CLOSED;
endpoint.failCount = 0;
// A ring buffer, holding the timestamp of each error. As we loop around the ring, the timestamp in the slot we're
// about to fill will tell us the error rate. That is, `maxFailure` number of requests in how many milliseconds?
endpoint.buffer = new Array(maxFailures - 1);
endpoint.bufferPointer = 0;
},
onEndpointReturned: function (endpoint, err) {
if (err) {
var oldestErrorTime, now;
if (endpoint.state === OPEN) {
return;
}
function getRollingWindowConfiguration(failureWindow, maxFailures, resetTimeout) {
return {
isInPool: isInPool,
onEndpointSelected: onEndpointSelected,
onEndpointRegistered: function (endpoint) {
endpoint.state = CLOSED;
// A ring buffer, holding the timestamp of each error. As we loop around the ring, the timestamp in the slot we're
// about to fill will tell us the error rate. That is, `maxFailure` number of requests in how many milliseconds?
endpoint.buffer = new RingBuffer(maxFailures - 1);
},
onEndpointReturned: function (endpoint, err) {
if (err) {
if (endpoint.state === OPEN) {
return;
}
if (endpoint.buffer.length === 0) {
disableEndpoint(endpoint);
return;
if (endpoint.buffer.size === 0) {
disableEndpoint(endpoint);
return;
}
var now = Date.now();
var oldestErrorTime = endpoint.buffer.read();
endpoint.buffer.write(now);
if (endpoint.state === HALF_OPEN_PENDING || (oldestErrorTime != null && now - oldestErrorTime <= failureWindow)) {
disableEndpoint(endpoint);
}
} else if (endpoint.state === HALF_OPEN_PENDING) {
endpoint.state = CLOSED;
}
}
};
}
oldestErrorTime = endpoint.buffer[endpoint.bufferPointer];
now = Date.now();
endpoint.buffer[endpoint.bufferPointer] = now;
endpoint.bufferPointer++;
endpoint.bufferPointer %= endpoint.buffer.length;
function getRateConfiguration(failureRate, failureRateWindow, resetTimeout) {
var maxErrorCount = failureRate * failureRateWindow;
return {
isInPool: isInPool,
onEndpointSelected: onEndpointSelected,
onEndpointRegistered: function (endpoint) {
endpoint.state = CLOSED;
endpoint.buffer = new RingBuffer(failureRateWindow);
endpoint.errors = 0;
},
onEndpointReturned: function (endpoint, err) {
var state = endpoint.state;
var newStatus = err ? 1 : 0;
var oldestStatus = endpoint.buffer.read() ? 1 : 0;
endpoint.buffer.write(newStatus);
endpoint.errors += newStatus - oldestStatus;
if (endpoint.state === HALF_OPEN_PENDING || (oldestErrorTime != null && now - oldestErrorTime <= failureWindow)) {
if (err && (state === HALF_OPEN_PENDING || endpoint.errors >= maxErrorCount)) {
disableEndpoint(endpoint);
} else if (!err && state === HALF_OPEN_PENDING) {
endpoint.state = CLOSED;
}
} else if (endpoint.state === HALF_OPEN_PENDING) {
endpoint.state = CLOSED;
}
}
})
};
}
}
};
function RingBuffer(size) {
this.buffer = new Array(size);
this.offset = 0;
this.size = size;
}
_.assign(RingBuffer.prototype, {
read: function () {
return this.buffer[this.offset];
},
write: function (val) {
this.buffer[this.offset] = val;
this.offset = (this.offset + 1) % this.size;
}
});

@@ -43,3 +43,3 @@ ## DNS Endpoint Pool

### `new DNSEndpointPool(serviceDiscoveryName, ttl, maxFailures, failureWindow, resetTimeout, onReady)`
### `new DNSEndpointPool(serviceDiscoveryName, ttl, circuitBreakerConfig, onReady)`

@@ -51,6 +51,11 @@ Creates a new pool object.

interval.
- `maxFailures`: how many failures from a single endpoint before it is removed from the pool.
- `failureWindow`: size of the sliding window of time in which the failures are counted.
- `resetTimeout`: the length of the window in which to record failures. Also the timeout before an endpoint will be
tried again.
- `circuitBreakerConfig`: optional configuration for circuit breaker behavior. If specified, errors on a particular endpoint will be tracked and bad endpoints removed from the pool. If none provided, no circuit breaker logic is applied. There are two different circuit-breaker behaviors available:
- Errors over time: the CB is configured with the an error threshold within a sliding time window. (eg: 5 errors in 10 seconds)
- `maxFailures`: how many failures from a single endpoint before it is removed from the pool.
- `failureWindow`: size of the sliding window of time in which the failures are counted.
- `resetTimeout`: The timeout before a failing endpoint will be re-entered to the pool and tried again.
- Error rate: the CB is configured with the percentage of errors within a sliding window of requests. (eg: 50% errors over 20 requests).
- `failureRate`: a number, `0 < n <= 1` that describes the rate at which the endpoint is disabled.
- `failureRateWindow`: the number of requests over which to calculate the failure rate.
- `resetTimeout`: The timeout before a failing endpoint will be re-entered to the pool and tried again.
- `onReady`: callback that will be executed after the list of endpoints is fetched for the first time. This does *not* guarantee that the endpoint list is not empty.

@@ -61,3 +66,3 @@

Returns the next active `endpoint` from the pool, or `null` if none are available. If none are available, the pool will
emit `'noEndpoints'`.
emit `'noEndpoints'`. If using circuit breakers, you _must_ call `endpoint.callback(err)` with the result of a call to this endpoint.

@@ -68,3 +73,3 @@ ### `pool.getStatus()`

- `total`: The total number of endpoints in the pool, in any status.
- `total`: The total number of endpoints in the pool, in any state.
- `unhealthy`: The number of endpoints which are unavailable (eg: due to their circuit breaker being open)

@@ -91,3 +96,7 @@ - `age`: The number of milliseconds since the last successful update of endpoints.

```js
var pool = new DNSEndpointPool('my.domain.example.com', 10000, 5, 10000, 10000);
var pool = new DNSEndpointPool('my.domain.example.com', 10000, {
maxFailures: 5,
failureWindow: 10000,
resetTimeout: 10000
});

@@ -94,0 +103,0 @@ pool.on('updateError', function (err) {

/*globals it, describe, beforeEach, afterEach */
var expect = require('expect.js'),
Sinon = require('sinon'),
DEP = require('./');
var expect = require('expect.js');
var Sinon = require('sinon');
var DEP = require('./');
describe('DNS Endpoint Pool', function () {
var stubs = [], clock;
var stubs = [];
var clock;
function autoRestore(stub) {

@@ -35,4 +36,5 @@ stubs.push(stub);

it('will automatically begin updating when constructed', function () {
var stub = autoRestore(Sinon.stub(DEP.prototype, 'update')),
dep = new DEP('foo.localhost', 5000);
/*eslint no-unused-vars: 0 */
var stub = autoRestore(Sinon.stub(DEP.prototype, 'update'));
var dep = new DEP('foo.localhost', 5000);
Sinon.assert.calledOnce(stub);

@@ -42,8 +44,7 @@ });

it('will execute a callback after the first update', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve')),
called = false,
dep;
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve'));
var called = false;
resolve.callsArgWith(0, null, []);
dep = new DEP('foo.localhost', 5000, null, function () {
var dep = new DEP('foo.localhost', 5000, null, function () {
called = true;

@@ -58,7 +59,6 @@ });

it('will update on a timer', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve')),
dep;
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve'));
resolve.callsArgWith(0, null, []);
dep = new DEP('foo.localhost', 5000);
var dep = new DEP('foo.localhost', 5000);

@@ -77,4 +77,3 @@ Sinon.assert.calledOnce(resolve);

it('will add resolved endpoints and serve them in rotation', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve')),
dep;
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve'));

@@ -85,3 +84,3 @@ resolve.callsArgWith(0, null, [

]);
dep = new DEP('foo.localhost', 5000);
var dep = new DEP('foo.localhost', 5000);

@@ -94,5 +93,3 @@ expect(dep.getEndpoint().url).to.be('bar.localhost:8000');

it('will trigger an error if resolving fails', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve')),
errorData,
dep;
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve'));

@@ -106,6 +103,7 @@ resolve

dep = new DEP('foo.localhost', 5000);
var dep = new DEP('foo.localhost', 5000);
expect(dep.getEndpoint().url).to.be('bar.localhost:8000');
var errorData;
dep.on('updateError', function (err) {

@@ -123,5 +121,3 @@ errorData = err;

it('will update with new endpoints returned', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve')),
bazEndpoint,
dep;
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve'));

@@ -137,6 +133,6 @@ resolve

]);
dep = new DEP('foo.localhost', 5000);
var dep = new DEP('foo.localhost', 5000);
dep.getEndpoint(); // bar
bazEndpoint = dep.getEndpoint();
var bazEndpoint = dep.getEndpoint();

@@ -155,4 +151,3 @@ expect(bazEndpoint.url).to.be('baz.localhost:8001');

it('can query the state of endpoints', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve')),
dep;
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve'));

@@ -164,3 +159,3 @@ resolve

dep = new DEP('foo.localhost', 5000);
var dep = new DEP('foo.localhost', 5000);

@@ -176,9 +171,2 @@ expect(dep.hasEndpoints()).to.be(false);

describe('with eject-on-error pool management', function () {
var ejectOnErrorConfig = {
maxFailures: 2,
failureWindow: 10000,
resetTimeout: 10000
};
it('enforces that config object has proper shape', function () {

@@ -188,85 +176,165 @@ autoRestore(Sinon.stub(DEP.prototype, 'update'));

function () { return new DEP('foo.localhost', 5000, { maxFailures: 2 }); },
function () { return new DEP('foo.localhost', 5000, { maxFailures: 2, failureWindow: 10000 }); }
function () { return new DEP('foo.localhost', 5000, { maxFailures: 2, failureWindow: 10000 }); },
function () { return new DEP('foo.localhost', 5000, { failureRate: 0.5 }); },
function () { return new DEP('foo.localhost', 5000, { failureRateWindow: 10 }); }
].forEach(function (fn) {
expect(fn).to.throwError('Must supply all arguments to ejectOnErrorPoolManager');
expect(fn).to.throwError('Must supply either configuration to ejectOnErrorPoolManager');
});
});
it('will remove endpoints from the pool if they fail', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve')),
barEndpoint,
bazEndpoint,
status,
dep;
describe('using time-based rolling window', function () {
var ejectOnErrorConfig = {
maxFailures: 2,
failureWindow: 10000,
resetTimeout: 10000
};
resolve.callsArgWith(0, null, [
{ name: 'bar.localhost', port: 8000 },
{ name: 'baz.localhost', port: 8001 }
]);
it('will remove endpoints from the pool if they fail', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve'));
dep = new DEP('foo.localhost', 5000, ejectOnErrorConfig);
resolve.callsArgWith(0, null, [
{ name: 'bar.localhost', port: 8000 },
{ name: 'baz.localhost', port: 8001 }
]);
barEndpoint = dep.getEndpoint();
barEndpoint.callback(true);
var dep = new DEP('foo.localhost', 5000, ejectOnErrorConfig);
bazEndpoint = dep.getEndpoint();
var barEndpoint = dep.getEndpoint();
barEndpoint.callback(true);
expect(dep.getEndpoint()).to.be(barEndpoint); // still in the pool
barEndpoint.callback(true);
var bazEndpoint = dep.getEndpoint();
expect(dep.getEndpoint()).to.be(bazEndpoint);
expect(dep.getEndpoint()).to.be(bazEndpoint); // bar is removed
expect(dep.getEndpoint()).to.be(barEndpoint); // still in the pool
barEndpoint.callback(true);
status = dep.getStatus();
expect(status.total).to.be(2);
expect(status.unhealthy).to.be(1);
expect(status.age).to.be.a('number');
expect(dep.getEndpoint()).to.be(bazEndpoint);
expect(dep.getEndpoint()).to.be(bazEndpoint); // bar is removed
dep.stopUpdating();
});
var status = dep.getStatus();
expect(status.total).to.be(2);
expect(status.unhealthy).to.be(1);
expect(status.age).to.be.a('number');
it('will reinstate endpoints for a single request after a timeout', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve')),
barEndpoint,
bazEndpoint,
dep;
dep.stopUpdating();
});
resolve.callsArgWith(0, null, [
{ name: 'bar.localhost', port: 8000 },
{ name: 'baz.localhost', port: 8001 }
]);
it('will reinstate endpoints for a single request after a timeout', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve'));
dep = new DEP('foo.localhost', 5000, ejectOnErrorConfig);
resolve.callsArgWith(0, null, [
{ name: 'bar.localhost', port: 8000 },
{ name: 'baz.localhost', port: 8001 }
]);
barEndpoint = dep.getEndpoint();
barEndpoint.callback(true);
barEndpoint.callback(true); // removed from pool.
var dep = new DEP('foo.localhost', 5000, ejectOnErrorConfig);
bazEndpoint = dep.getEndpoint();
var barEndpoint = dep.getEndpoint();
barEndpoint.callback(true);
barEndpoint.callback(true); // removed from pool.
clock.tick(10000);
var bazEndpoint = dep.getEndpoint();
expect(dep.getEndpoint()).to.be(barEndpoint);
expect(dep.getEndpoint()).to.be(bazEndpoint);
expect(dep.getEndpoint()).to.be(bazEndpoint); // only return barEndpoint once
clock.tick(10000);
barEndpoint.callback(null); // denotes success
expect(dep.getEndpoint()).to.be(barEndpoint); // it's back in the game
dep.stopUpdating();
expect(dep.getEndpoint()).to.be(barEndpoint);
expect(dep.getEndpoint()).to.be(bazEndpoint);
expect(dep.getEndpoint()).to.be(bazEndpoint); // only return barEndpoint once
barEndpoint.callback(null); // denotes success
expect(dep.getEndpoint()).to.be(barEndpoint); // it's back in the game
dep.stopUpdating();
});
it('reports the age of the endpoints when updates fail', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve'));
var errorHandler = Sinon.spy();
var errObj = { error: true };
// works on the first and fourth calls, fails every other time
resolve
.callsArgWith(0, errObj)
.onFirstCall().callsArgWith(0, null, [
{ name: 'bar.localhost', port: 8000 },
{ name: 'baz.localhost', port: 8001 }
])
.onCall(3).callsArgWith(0, null, [
{ name: 'bar.localhost', port: 8000 },
{ name: 'baz.localhost', port: 8001 }
]);
var dep = new DEP('foo.localhost', 5000, ejectOnErrorConfig); // call 1
dep.on('updateError', errorHandler);
clock.tick(5000); // call 2
clock.tick(5000); // call 3
clock.tick(5000); // call 4, should reset the timer
clock.tick(5000); // call 5
Sinon.assert.calledThrice(errorHandler);
expect(errorHandler.firstCall.calledWithExactly(errObj, 5000)).to.be(true);
expect(errorHandler.secondCall.calledWithExactly(errObj, 10000)).to.be(true);
expect(errorHandler.thirdCall.calledWithExactly(errObj, 5000)).to.be(true);
dep.stopUpdating();
});
});
it('reports the age of the endpoints when updates fail', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve')),
errorHandler = Sinon.spy(),
errObj = { error: true },
dep;
describe('using percentage error rates', function () {
var ejectOnErrorConfig = {
failureRate: 1,
failureRateWindow: 2,
resetTimeout: 10000
};
// works on the first and fourth calls, fails every other time
resolve
.callsArgWith(0, errObj)
.onFirstCall().callsArgWith(0, null, [
it('will remove endpoints from the pool if they fail', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve'));
resolve.callsArgWith(0, null, [
{ name: 'bar.localhost', port: 8000 },
{ name: 'baz.localhost', port: 8001 }
])
.onCall(3).callsArgWith(0, null, [
]);
var dep = new DEP('foo.localhost', 5000, ejectOnErrorConfig);
var barEndpoint = dep.getEndpoint();
barEndpoint.callback(true);
var bazEndpoint = dep.getEndpoint();
expect(dep.getEndpoint()).to.be(barEndpoint); // still in the pool
barEndpoint.callback(true);
expect(dep.getEndpoint()).to.be(bazEndpoint);
expect(dep.getEndpoint()).to.be(bazEndpoint); // bar is removed
var status = dep.getStatus();
expect(status.total).to.be(2);
expect(status.unhealthy).to.be(1);
expect(status.age).to.be.a('number');
dep.stopUpdating();
});
it('will remove an endpoint from the pool once it reaches its error threshold', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve'));
resolve.callsArgWith(0, null, [
{ name: 'bar.localhost', port: 8000 }
]);
var dep = new DEP('foo.localhost', 5000, {
failureRate: 0.75,
failureRateWindow: 4,
resetTimeout: 10000
});
var endpoint = dep.getEndpoint();
endpoint.callback(true);
endpoint = dep.getEndpoint();
endpoint.callback(true);
endpoint = dep.getEndpoint();
endpoint.callback(true);
expect(dep.getEndpoint()).to.be(null);
});
it('will reinstate endpoints for a single request after a timeout', function () {
var resolve = autoRestore(Sinon.stub(DEP.prototype, 'resolve'));
resolve.callsArgWith(0, null, [
{ name: 'bar.localhost', port: 8000 },

@@ -276,18 +344,26 @@ { name: 'baz.localhost', port: 8001 }

dep = new DEP('foo.localhost', 5000, ejectOnErrorConfig); // call 1
dep.on('updateError', errorHandler);
clock.tick(5000); // call 2
clock.tick(5000); // call 3
clock.tick(5000); // call 4, should reset the timer
clock.tick(5000); // call 5
var dep = new DEP('foo.localhost', 5000, {
failureRate: 1,
failureRateWindow: 2,
resetTimeout: 10000
});
Sinon.assert.calledThrice(errorHandler);
var barEndpoint = dep.getEndpoint();
barEndpoint.callback(true);
barEndpoint.callback(true); // removed from pool.
expect(errorHandler.firstCall.calledWithExactly(errObj, 5000)).to.be(true);
expect(errorHandler.secondCall.calledWithExactly(errObj, 10000)).to.be(true);
expect(errorHandler.thirdCall.calledWithExactly(errObj, 5000)).to.be(true);
dep.stopUpdating();
var bazEndpoint = dep.getEndpoint();
clock.tick(10000);
expect(dep.getEndpoint()).to.be(barEndpoint);
expect(dep.getEndpoint()).to.be(bazEndpoint);
expect(dep.getEndpoint()).to.be(bazEndpoint); // only return barEndpoint once
barEndpoint.callback(null); // denotes success
expect(dep.getEndpoint()).to.be(barEndpoint); // it's back in the game
dep.stopUpdating();
});
});
});
});

Sorry, the diff of this file is not supported yet

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