elastic-apm-http-client
Advanced tools
Comparing version 10.0.0 to 10.1.0
# elastic-apm-http-client changelog | ||
## v10.1.0 | ||
- Fix client handling of an AWS Lambda environment: | ||
1. `client.flush()` will initiate a quicker completion of the current intake | ||
request. | ||
2. The process 'beforeExit' event is *not* used to start a graceful shutdown | ||
of the client, because the Lambda Runtime sometimes uses 'beforeExit' to | ||
handle *freezing* of the Lambda VM instance. That VM instance is typically | ||
unfrozen and used again, for which this Client is still needed. | ||
## v10.0.0 | ||
@@ -4,0 +14,0 @@ |
68
index.js
@@ -48,17 +48,26 @@ 'use strict' | ||
const isLambdaExecutionEnvironment = !!process.env.AWS_LAMBDA_FUNCTION_NAME | ||
// All sockets on the agent are unreffed when they are created. This means that | ||
// when those are the only handles left, the `beforeExit` event will be | ||
// emitted. By listening for this we can make sure to end the requests properly | ||
// before exiting. This way we don't keep the process running until the `time` | ||
// timeout happens. | ||
// when the user process's event loop is done, and these are the only handles | ||
// left, the process 'beforeExit' event will be emitted. By listening for this | ||
// we can make sure to end the requests properly before process exit. This way | ||
// we don't keep the process running until the `time` timeout happens. | ||
// | ||
// An exception to this is AWS Lambda which, in some cases (sync function | ||
// handlers that use a callback), will wait for 'beforeExit' to freeze the | ||
// Lambda instance VM *for later re-use*. This means we never want to shutdown | ||
// the `Client` on 'beforeExit'. | ||
const clientsToAutoEnd = [] | ||
process.once('beforeExit', function () { | ||
clientsToAutoEnd.forEach(function (client) { | ||
if (!client) { | ||
// Clients remove themselves from the array when they end. | ||
return | ||
} | ||
client._gracefulExit() | ||
if (!isLambdaExecutionEnvironment) { | ||
process.once('beforeExit', function () { | ||
clientsToAutoEnd.forEach(function (client) { | ||
if (!client) { | ||
// Clients remove themselves from the array when they end. | ||
return | ||
} | ||
client._gracefulExit() | ||
}) | ||
}) | ||
}) | ||
} | ||
@@ -438,3 +447,2 @@ util.inherits(Client, Writable) | ||
const t = process.hrtime() | ||
// XXX perf: elims `encodeObject` stack frame; faster loop | ||
const chunks = [] | ||
@@ -472,2 +480,8 @@ for (var i = 0; i < objs.length; i++) { | ||
if (this._active) { | ||
// In a Lambda environment a flush is almost certainly a signal that the | ||
// runtime environment is about to be frozen: tell the intake request | ||
// to finish up quickly. | ||
if (this._intakeRequestGracefulExitFn && isLambdaExecutionEnvironment) { | ||
this._intakeRequestGracefulExitFn() | ||
} | ||
this._onflushed = cb | ||
@@ -716,3 +730,5 @@ this._chopper.chop() | ||
let intakeRes | ||
let intakeReqSocket = null | ||
let intakeResTimer = null | ||
let intakeRequestGracefulExitCalled = false | ||
const intakeResTimeout = client._conf.intakeResTimeout | ||
@@ -779,7 +795,2 @@ const intakeResTimeoutOnEnd = client._conf.intakeResTimeoutOnEnd | ||
client._active = false | ||
if (client._onflushed) { | ||
client._onflushed() | ||
client._onflushed = null | ||
} | ||
const backoffDelayMs = client._getBackoffDelay(!!err) | ||
@@ -794,2 +805,7 @@ if (err) { | ||
} | ||
if (client._onflushed) { | ||
client._onflushed() | ||
client._onflushed = null | ||
} | ||
if (backoffDelayMs > 0) { | ||
@@ -805,3 +821,9 @@ setTimeout(next, backoffDelayMs).unref() | ||
client._intakeRequestGracefulExitFn = () => { | ||
intakeRequestGracefulExitCalled = true | ||
if (intakeReqSocket) { | ||
log.trace('_intakeRequestGracefulExitFn: re-ref intakeReqSocket') | ||
intakeReqSocket.ref() | ||
} | ||
if (intakeResTimer) { | ||
log.trace('_intakeRequestGracefulExitFn: reset intakeResTimer to short timeout') | ||
clearTimeout(intakeResTimer) | ||
@@ -835,2 +857,3 @@ intakeResTimer = setTimeout(() => { | ||
intakeReq.on('socket', function (socket) { | ||
intakeReqSocket = socket | ||
// Unref the socket for this request so that the Client does not keep | ||
@@ -844,4 +867,6 @@ // the node process running if it otherwise would be done. (This is | ||
// manually unref the socket. | ||
log.trace('intakeReq "socket": unref it') | ||
socket.unref() | ||
if (!intakeRequestGracefulExitCalled) { | ||
log.trace('intakeReq "socket": unref it') | ||
intakeReqSocket.unref() | ||
} | ||
}) | ||
@@ -928,3 +953,4 @@ | ||
if (!completedFromPart.intakeReq && !completedFromPart.intakeRes) { | ||
const timeout = client._writableState.ending ? intakeResTimeoutOnEnd : intakeResTimeout | ||
const timeout = (client._writableState.ending || intakeRequestGracefulExitCalled | ||
? intakeResTimeoutOnEnd : intakeResTimeout) | ||
log.trace({ timeout }, 'start intakeResTimer') | ||
@@ -931,0 +957,0 @@ intakeResTimer = setTimeout(() => { |
{ | ||
"name": "elastic-apm-http-client", | ||
"version": "10.0.0", | ||
"version": "10.1.0", | ||
"description": "A low-level HTTP client for communicating with the Elastic APM intake API", | ||
@@ -14,3 +14,3 @@ "main": "index.js", | ||
"scripts": { | ||
"test": "standard && nyc tape \"test/*.js\"" | ||
"test": "standard && nyc tape \"test/*.test.js\"" | ||
}, | ||
@@ -17,0 +17,0 @@ "engines": { |
@@ -345,7 +345,9 @@ # elastic-apm-http-client | ||
Flush the internal buffer and end the current HTTP request to the APM | ||
Server. If no HTTP request is in process nothing happens. | ||
Server. If no HTTP request is in process nothing happens. In an AWS Lambda | ||
environment this will also initiate a quicker shutdown of the intake request, | ||
because the APM agent always flushes at the end of a Lambda handler. | ||
Arguments: | ||
- `callback` - Callback is called when the internal buffer have been | ||
- `callback` - Callback is called when the internal buffer has been | ||
flushed and the HTTP request ended. If no HTTP request is in progress | ||
@@ -352,0 +354,0 @@ the callback is called in the next tick. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
79097
1553
375
3