Skip to content

Commit 4a30d5c

Browse files
authored
fix: Fixed issue with bluebird and when instrumentation where checking active context crashed when transaction prematurely ends (#2909)
1 parent 8d8608d commit 4a30d5c

File tree

4 files changed

+70
-7
lines changed

4 files changed

+70
-7
lines changed

lib/instrumentation/when/contextualizer.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ Contextualizer.prototype = Object.create(null)
116116
Contextualizer.prototype.isActive = function isActive() {
117117
const segments = this.context.segments
118118
const segment = segments[this.idx] || segments[this.parentIdx] || segments[0]
119-
return segment && this.context.transaction.isActive()
119+
const transaction = this.getTransaction()
120+
return segment && transaction?.isActive()
120121
}
121122

122123
/**

lib/shim/promise-shim.js

+5-6
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ class PromiseShim extends Shim {
121121
const transaction = shim.tracer.getTransaction()
122122
// This extra property is added by `_wrapExecutorContext` in the pre step.
123123
const executor = args[0]
124-
const context = executor && executor[symbols.executorContext]
124+
const context = executor?.[symbols.executorContext]
125125
if (!context || !shim.isFunction(context.executor)) {
126126
return
127127
}
@@ -387,9 +387,7 @@ function _wrapExecutorContext(shim, args) {
387387
function _wrapResolver(context, fn) {
388388
return function wrappedResolveReject(val) {
389389
const promise = context.promise
390-
if (promise && promise[symbols.context]) {
391-
promise[symbols.context].getSegment().touch()
392-
}
390+
promise?.[symbols.context]?.getSegment()?.touch()
393391
fn(val)
394392
}
395393
}
@@ -416,7 +414,7 @@ function wrapHandler({ handler, index, argsLength, useAllParams, ctx, shim }) {
416414
}
417415

418416
return function __NR_wrappedThenHandler() {
419-
if (!ctx.handler || !ctx.handler[symbols.context]) {
417+
if (!ctx?.handler?.[symbols.context]) {
420418
return handler.apply(this, arguments)
421419
}
422420

@@ -591,7 +589,8 @@ class Contextualizer {
591589
isActive() {
592590
const segments = this.context.segments
593591
const segment = segments[this.idx] || segments[this.parentIdx] || segments[0]
594-
return segment && this.context.transaction.isActive()
592+
const transaction = this.getTransaction()
593+
return segment && transaction?.isActive()
595594
}
596595

597596
getTransaction() {

test/lib/promises/transaction-state.js

+17
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,21 @@ module.exports = async function runTests({ t, agent, Promise, library }) {
158158
})
159159
await plan.completed
160160
})
161+
162+
await t.test('does not propagate context when transaction ends prematurely', async function (t) {
163+
const plan = tspl(t, { plan: 2 })
164+
165+
helper.runInTransaction(agent, function transactionWrapper(transaction) {
166+
transaction.end()
167+
Promise.resolve(0)
168+
.then(function step1() {
169+
plan.equal(agent.getTransaction(), null)
170+
return 1
171+
})
172+
.then(function rejector(val) {
173+
plan.equal(val, 1)
174+
})
175+
})
176+
await plan.completed
177+
})
161178
}

test/unit/shim/promise-shim.test.js

+46
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,22 @@ test('PromiseShim', async (t) => {
469469
})
470470
})
471471
})
472+
473+
await t.test('should not link context through to thenned callbacks when transaction ends before Promise calls', (t, end) => {
474+
const { agent, shim, TestPromise } = t.nr
475+
shim.setClass(TestPromise)
476+
shim.wrapCast(TestPromise, 'resolve')
477+
shim.wrapThen(TestPromise.prototype, 'then')
478+
479+
helper.runInTransaction(agent, (tx) => {
480+
tx.end()
481+
TestPromise.resolve().then(() => {
482+
assert.equal(agent.getTransaction(), null)
483+
assert.equal(shim.getActiveSegment(), null)
484+
end()
485+
})
486+
})
487+
})
472488
})
473489

474490
await t.test('#wrapThen', async (t) => {
@@ -519,6 +535,21 @@ test('PromiseShim', async (t) => {
519535
})
520536
})
521537

538+
await t.test('should not link context through to thenned callbacks when transaction ends before Promise calls', (t, end) => {
539+
const { agent, shim, TestPromise } = t.nr
540+
shim.setClass(TestPromise)
541+
shim.wrapThen(TestPromise.prototype, 'then')
542+
543+
helper.runInTransaction(agent, (tx) => {
544+
tx.end()
545+
TestPromise.resolve().then(() => {
546+
assert.equal(agent.getTransaction(), null)
547+
assert.equal(shim.getActiveSegment(), null)
548+
end()
549+
})
550+
})
551+
})
552+
522553
await t.test('should wrap both handlers', (t) => {
523554
const { shim, TestPromise } = t.nr
524555
shim.setClass(TestPromise)
@@ -584,6 +615,21 @@ test('PromiseShim', async (t) => {
584615
})
585616
})
586617

618+
await t.test('should not link context through to thenned callbacks when transaction ends before promise calls', (t, end) => {
619+
const { agent, shim, TestPromise } = t.nr
620+
shim.setClass(TestPromise)
621+
shim.wrapCatch(TestPromise.prototype, 'catch')
622+
623+
helper.runInTransaction(agent, (tx) => {
624+
tx.end()
625+
TestPromise.reject().catch(() => {
626+
assert.equal(agent.getTransaction(), null)
627+
assert.equal(shim.getActiveSegment(), null)
628+
end()
629+
})
630+
})
631+
})
632+
587633
await t.test('should only wrap the rejection handler', (t) => {
588634
const { shim, TestPromise } = t.nr
589635
shim.setClass(TestPromise)

0 commit comments

Comments
 (0)