Hi, I'm trying to use APM in a small module and running into the following problem - I start and close a transaction manually, but spans (both custom and from instrumented MongoDB query) are sent after the transaction is closed.
Here is code sample:
// some imports
const transaction = apmWrapper.agent.startTransaction('test-apm-2', 'job');
const span = transaction.startSpan('my-span', 'task');
MongoDb
.connect()
.then(() => UserCollection.find({}).limit(1).toArray())
.then(([user]) => logger.warn(user.nick))
.then(() => {
span.end();
transaction.end('done');
return apmWrapper.flush(); // wraps callback into a promise
})
.then(() => ShutdownHelper.exit(0))
.catch(e => {
logger.error('Rating epic fail', e);
ShutdownHelper.exit(1);
});
So I'd expect all spans to be closed and sent before the transaction is closed, as soon as they doesn't return any promise to wait on, so I presume they work synchronously.
But here is what I got in the debug log:
Debug log
adding hook to Node.js module loader
shimming mongodb-core@3.1.9 module
shimming mongodb-core.Server.prototype.command
shimming mongodb-core.Server.prototype functions: [ 'insert', 'update', 'remove', 'auth' ]
shimming mongodb-core.Cursor.prototype functions: [ '_find', '_getmore' ]
shimming bluebird@3.5.1 module
shimming bluebird.prototype functions: [ '_then', '_addCallbacks' ]
shimming bluebird.config
start trace { trans: '9f24bea44d26b2f5',
parent: undefined,
trace: '731b9ee10e9b6e2cb33983ce6c486cb6',
name: 'test-apm-2',
type: 'job' }
start span { span: '7fefd10fc85d38e2',
parent: '9f24bea44d26b2f5',
trace: '731b9ee10e9b6e2cb33983ce6c486cb6',
name: 'my-span',
type: 'task' }
intercepted call to mongodb-core.Cursor.prototype._find { id: '9f24bea44d26b2f5' }
start span { span: '27125da8ceb6754d',
parent: '7fefd10fc85d38e2',
trace: '731b9ee10e9b6e2cb33983ce6c486cb6',
name: 'speke-local-1.users.find',
type: 'db.mongodb.query' }
intercepted mongodb-core.Cursor.prototype._find callback { id: '9f24bea44d26b2f5' }
ended span { span: '27125da8ceb6754d',
parent: '7fefd10fc85d38e2',
trace: '731b9ee10e9b6e2cb33983ce6c486cb6',
name: 'speke-local-1.users.find',
type: 'db.mongodb.query' }
encoding span { span: '27125da8ceb6754d',
parent: '7fefd10fc85d38e2',
trace: '731b9ee10e9b6e2cb33983ce6c486cb6',
name: 'speke-local-1.users.find',
type: 'db.mongodb.query' }
warn: SomeUserNick
ended span { span: '7fefd10fc85d38e2',
parent: '9f24bea44d26b2f5',
trace: '731b9ee10e9b6e2cb33983ce6c486cb6',
name: 'my-span',
type: 'task' }
encoding span { span: '7fefd10fc85d38e2',
parent: '9f24bea44d26b2f5',
trace: '731b9ee10e9b6e2cb33983ce6c486cb6',
name: 'my-span',
type: 'task' }
setting transaction result { trans: '9f24bea44d26b2f5',
parent: undefined,
trace: '731b9ee10e9b6e2cb33983ce6c486cb6',
result: 'done' }
sending transaction { trans: '9f24bea44d26b2f5',
trace: '731b9ee10e9b6e2cb33983ce6c486cb6' }
ended transaction { trans: '9f24bea44d26b2f5',
parent: undefined,
trace: '731b9ee10e9b6e2cb33983ce6c486cb6',
type: 'job',
result: 'done',
name: 'test-apm-2' }
sending span { span: '7fefd10fc85d38e2',
parent: '9f24bea44d26b2f5',
trace: '731b9ee10e9b6e2cb33983ce6c486cb6',
name: 'my-span',
type: 'task' }
sending span { span: '27125da8ceb6754d',
parent: '7fefd10fc85d38e2',
trace: '731b9ee10e9b6e2cb33983ce6c486cb6',
name: 'speke-local-1.users.find',
type: 'db.mongodb.query' }
As you can see at the end of the log, spans are sent after the transaction is closed, so I see an empty transaction in the UI, without any spans.
And if I just add a small 10ms timeout before ending the transaction, it all works perfectly fine.
.then(() => new Promise(resolve => setTimeout(resolve, 10)))
.then(() => {
transaction.end('done');
return apmWrapper.flush();
})
But it does seem like a wrong way.
Could anyone please explain why this is happening and maybe advise a correct way of achieving my goal?