Skip to content

Commit

Permalink
fix: always end transaction when socket is closed prematurely (#1439)
Browse files Browse the repository at this point in the history
This fixes a race condition that in some cases meant that a request
transaction was never ended if the underlying TCP socket was closed by
the client and the server didn't discover this in time.

Fixes #1411
  • Loading branch information
watson authored Oct 9, 2019
1 parent a429699 commit 69a7b68
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 7 deletions.
10 changes: 7 additions & 3 deletions lib/instrumentation/http-shared.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ exports.instrumentRequest = function (agent, moduleName) {
ins.bindEmitter(res)

endOfStream(res, function (err) {
if (trans.ended) return
if (!err) return trans.end()

if (agent._conf.errorOnAbortedRequests && !trans.ended) {
if (agent._conf.errorOnAbortedRequests) {
var duration = trans._timer.elapsed()
if (duration > (agent._conf.abortedErrorThreshold * 1000)) {
agent.captureError('Socket closed with active HTTP request (>' + agent._conf.abortedErrorThreshold + ' sec)', {
Expand All @@ -49,9 +50,12 @@ exports.instrumentRequest = function (agent, moduleName) {

// Handle case where res.end is called after an error occurred on the
// stream (e.g. if the underlying socket was prematurely closed)
res.on('prefinish', function () {
const end = res.end
res.end = function () {
const result = end.apply(this, arguments)
trans.end()
})
return result
}
})
}
}
Expand Down
9 changes: 5 additions & 4 deletions test/instrumentation/modules/http/aborted-requests-enabled.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,13 @@ test('client-side abort below error threshold - call end', { timeout: 10000 }, f
var server = http.createServer(function (req, res) {
setTimeout(function () {
clientReq.abort()
setTimeout(function () {
res.write('Hello') // server emits clientError if written in same tick as abort
res.write('sync write')
process.nextTick(function () {
res.write('nextTick write')
setTimeout(function () {
res.end(' World')
res.end('setTimeout write')
}, 10)
}, 10)
})
}, (agent._conf.abortedErrorThreshold * 1000) / 2)
})

Expand Down

0 comments on commit 69a7b68

Please sign in to comment.