Socket
Socket
Sign inDemoInstall

hot-shots

Package Overview
Dependencies
Maintainers
1
Versions
90
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

hot-shots - npm Package Compare versions

Comparing version 8.1.0 to 8.2.0

3

CHANGES.md
CHANGELOG
=========
## 8.2.0 (2020-9-30)
* @dhermes Making UDS error handling and recovery more robust. Note these look to be ok in a minor release but are signficant upgrades to how UDS works. Thanks as well to @prognant for an overlapping PR.
## 8.1.0 (2020-9-25)

@@ -5,0 +8,0 @@ * @maleblond Support multiple values for the same tag key

@@ -0,1 +1,4 @@

const os = require('os'),
process = require('process');
exports.PROTOCOL = {

@@ -7,1 +10,27 @@ TCP: 'tcp',

};
/**
* Determines error codes that signify a connection to a Unix Domain Socket (UDS)
* has failed in a way that can be retried. This codes are OS-specific.
* @returns {number[]} An array of the error codes.
*/
function udsErrors() {
if (process.platform === 'linux') {
return [
os.constants.errno.ENOTCONN,
os.constants.errno.ECONNREFUSED,
];
}
if (process.platform === 'darwin') {
return [
os.constants.errno.EDESTADDRREQ,
os.constants.errno.ECONNRESET,
];
}
// Unknown / not yet implemented
return [];
}
exports.udsErrors = udsErrors;

152

lib/statsd.js

@@ -1,8 +0,11 @@

const util = require('util'),
const process = require('process'),
util = require('util'),
helpers = require('./helpers'),
applyStatsFns = require('./statsFunctions');
const { PROTOCOL } = require('./constants');
const constants = require('./constants');
const createTransport = require('./transport');
const PROTOCOL = constants.PROTOCOL;
const UDS_ERROR_CODES = constants.udsErrors();
const UDS_DEFAULT_GRACEFUL_RESTART_LIMIT = 1000;

@@ -51,2 +54,4 @@ const CACHE_DNS_TTL_DEFAULT = 60000;

this.port = options.port || parseInt(process.env.DD_DOGSTATSD_PORT, 10) || 8125;
this.path = options.path;
this.stream = options.stream;
this.prefix = options.prefix || '';

@@ -72,2 +77,4 @@ this.suffix = options.suffix || '';

this.udsGracefulErrorHandling = 'udsGracefulErrorHandling' in options ? options.udsGracefulErrorHandling : true;
this.udsGracefulRestartRateLimit = options.udsGracefulRestartRateLimit || UDS_DEFAULT_GRACEFUL_RESTART_LIMIT; // only recreate once per second
this.isChild = options.isChild;

@@ -99,12 +106,4 @@ // If we're mocking the client, create a buffer to record the outgoing calls.

if (! this.socket) {
this.socket = createTransport(this, {
host: this.host,
cacheDns: this.cacheDns,
cacheDnsTtl: this.cacheDnsTtl,
path: options.path,
port: this.port,
protocol: this.protocol,
stream: options.stream
});
if (!this.socket) {
trySetNewSocket(this);
}

@@ -125,39 +124,7 @@

// does not support options.isChild (how to re-create a socket you didn't create?)
if (this.socket && !options.isChild && options.protocol === PROTOCOL.UDS && this.udsGracefulErrorHandling) {
const socketCreateLimit = options.udsGracefulRestartRateLimit || UDS_DEFAULT_GRACEFUL_RESTART_LIMIT; // only recreate once per second
if (this.socket && options.protocol === PROTOCOL.UDS) {
const lastSocketCreateTime = Date.now();
this.socket.on('error', (err) => {
const code = err.code;
switch (code) {
case 107:
case 111: {
if (Date.now() - lastSocketCreateTime >= socketCreateLimit) {
// recreate the socket, but only once per 30 seconds
if (this.errorHandler) {
this.socket.removeListener('error', this.errorHandler);
}
this.socket.close();
this.socket = createTransport(this, {
host: this.host,
path: options.path,
port: this.port,
protocol: this.protocol
});
if (this.errorHandler) {
this.socket.on('error', this.errorHandler);
} else {
this.socket.on('error', error => console.error(`hot-shots UDS error: ${error}`));
}
}
break;
}
default: {
break;
}
}
});
maybeAddUDSErrorHandler(this, lastSocketCreateTime);
}
this.messagesInFlight = 0;

@@ -361,3 +328,12 @@ this.CHECKS = {

if (!this.socket) {
const socketWasMissing = !this.socket;
if (socketWasMissing && this.protocol === PROTOCOL.UDS) {
trySetNewSocket(this);
if (this.socket) {
// On success, add custom UDS error handling.
maybeAddUDSErrorHandler(this, Date.now());
}
}
if (socketWasMissing) {
const error = new Error('Socket not created properly. Check previous errors for details.');

@@ -534,1 +510,83 @@ if (callback) {

exports.StatsD = Client;
/**
* Handle an error connecting to a Unix Domain Socket (UDS). This will
* attempt to create a new socket and replace and close the client's current
* socket, registering a **new** `udsErrorHandler()` on the newly created socket.
* If a new socket can't be created (e.g. if no UDS currently exists at
* `client.path`) then this will leave the existing socket intact.
*
* Note that this will no-op with an early exit if the last socket create time
* was too recent (within the UDS graceful restart rate limit).
* @param client Client The statsd Client that may be getting a UDS error handler.
* @param lastSocketCreateTime number The timestamp (in milliseconds since the
* epoch) when the current socket was created.
*/
function udsErrorHandler(client, lastSocketCreateTime) {
// recreate the socket, but only once within `udsGracefulRestartRateLimit`.
if (Date.now() - lastSocketCreateTime < client.udsGracefulRestartRateLimit) {
return;
}
if (client.errorHandler) {
client.socket.removeListener('error', client.errorHandler);
}
const newSocket = createTransport(client, {
host: client.host,
path: client.path,
port: client.port,
protocol: client.protocol,
});
if (newSocket) {
client.socket.close();
client.socket = newSocket;
maybeAddUDSErrorHandler(client, Date.now());
} else {
console.error('Could not replace UDS connection with new socket');
return;
}
if (client.errorHandler) {
client.socket.on('error', client.errorHandler);
} else {
client.socket.on('error', (error) => console.error(`hot-shots UDS error: ${error}`));
}
}
/**
* Add a Unix Domain Socket (UDS) error handler to the client's socket, if the
* client is not a "child" client and has graceful error handling enabled for
* UDS.
* @param client Client The statsd Client that may be getting a UDS error handler.
* @param lastSocketCreateTime number The timestamp (in milliseconds since the
* epoch) when the current socket was created.
*/
function maybeAddUDSErrorHandler(client, lastSocketCreateTime) {
if (client.isChild || !client.udsGracefulErrorHandling) {
return;
}
client.socket.on('error', (err) => {
if (UDS_ERROR_CODES.includes(-err.code)) {
udsErrorHandler(client, lastSocketCreateTime);
}
});
}
/**
* Try to replace a client's socket with a new transport. If `createTransport()`
* returns `null` this will still set the client's socket to `null`.
* @param client Client The statsd Client that will be getting a new socket
*/
function trySetNewSocket(client) {
client.socket = createTransport(client, {
host: client.host,
cacheDns: client.cacheDns,
cacheDnsTtl: client.cacheDnsTtl,
path: client.path,
port: client.port,
protocol: client.protocol,
stream: client.stream,
});
}
{
"name": "hot-shots",
"description": "Node.js client for StatsD, DogStatsD, and Telegraf",
"version": "8.1.0",
"version": "8.2.0",
"author": "Steve Ivy",

@@ -6,0 +6,0 @@ "types": "./types.d.ts",

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