Skip to content

Commit

Permalink
More details on uncaught exceptions and unawaited async (#207)
Browse files Browse the repository at this point in the history
* more details on exceptions

* fix tests
  • Loading branch information
mhoeger committed May 13, 2019
1 parent 07e4a39 commit 86314a8
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 11 deletions.
18 changes: 10 additions & 8 deletions src/Context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,23 @@ class InvocationContext implements Context {

constructor(info: FunctionInfo, request: rpc.IInvocationRequest, logCallback: LogCallback, callback: ResultCallback) {
this.invocationId = <string>request.invocationId;
this.executionContext = {
const executionContext = {
invocationId: this.invocationId,
functionName: <string>info.name,
functionDirectory: <string>info.directory
};
this.executionContext = executionContext;
this.bindings = {};
let _done = false;
let _promise = false;

this.log = Object.assign(
<ILog>(...args: any[]) => logWithAsyncCheck(_done, logCallback, LogLevel.Information, ...args),
<ILog>(...args: any[]) => logWithAsyncCheck(_done, logCallback, LogLevel.Information, executionContext, ...args),
{
error: <ILog>(...args: any[]) => logWithAsyncCheck(_done, logCallback, LogLevel.Error, ...args),
warn: <ILog>(...args: any[]) => logWithAsyncCheck(_done, logCallback, LogLevel.Warning, ...args),
info: <ILog>(...args: any[]) => logWithAsyncCheck(_done, logCallback, LogLevel.Information, ...args),
verbose: <ILog>(...args: any[]) => logWithAsyncCheck(_done, logCallback, LogLevel.Trace, ...args)
error: <ILog>(...args: any[]) => logWithAsyncCheck(_done, logCallback, LogLevel.Error, executionContext, ...args),
warn: <ILog>(...args: any[]) => logWithAsyncCheck(_done, logCallback, LogLevel.Warning, executionContext, ...args),
info: <ILog>(...args: any[]) => logWithAsyncCheck(_done, logCallback, LogLevel.Information, executionContext, ...args),
verbose: <ILog>(...args: any[]) => logWithAsyncCheck(_done, logCallback, LogLevel.Trace, executionContext, ...args)
}
);

Expand Down Expand Up @@ -98,9 +99,10 @@ class InvocationContext implements Context {
}

// Emit warning if trying to log after function execution is done.
function logWithAsyncCheck(done: boolean, log: LogCallback, level: LogLevel, ...args: any[]) {
function logWithAsyncCheck(done: boolean, log: LogCallback, level: LogLevel, executionContext: ExecutionContext, ...args: any[]) {
if (done) {
let badAsyncMsg = "Warning: Unexpected call to 'log' on the context object after function execution has completed. Please check for asynchronous calls that are not awaited or calls to 'done' made before function execution completes.";
let badAsyncMsg = "Warning: Unexpected call to 'log' on the context object after function execution has completed. Please check for asynchronous calls that are not awaited or calls to 'done' made before function execution completes. ";
badAsyncMsg += `Function name: ${executionContext.functionName}. Invocation Id: ${executionContext.invocationId}.`;
log(LogLevel.Warning, badAsyncMsg);
systemWarn(badAsyncMsg);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export function startNodeWorker(args) {
});

process.on('uncaughtException', err => {
systemError(`Worker ${workerId} uncaught exception: `, err);
systemError(`Worker ${workerId} uncaught exception: ${err}`, err.stack);
process.exit(1);
});
process.on('exit', code => {
Expand Down
4 changes: 2 additions & 2 deletions test/ContextTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ describe('Context', () => {
callUserFunc(BasicCallback.callbackOnce, _context);
_context.log("");
sinon.assert.calledTwice(_logger);
sinon.assert.calledWith(_logger, rpc.RpcLog.Level.Warning, "Warning: Unexpected call to 'log' on the context object after function execution has completed. Please check for asynchronous calls that are not awaited or calls to 'done' made before function execution completes.");
sinon.assert.calledWith(_logger, rpc.RpcLog.Level.Warning, "Warning: Unexpected call to 'log' on the context object after function execution has completed. Please check for asynchronous calls that are not awaited or calls to 'done' made before function execution completes. Function name: test. Invocation Id: 1.");
});

it ('function logs error on calling context.log from non-awaited async call', async () => {
await callUserFunc(BasicAsync.asyncPlainFunction, _context);
_context.log("");
sinon.assert.calledTwice(_logger);
sinon.assert.calledWith(_logger, rpc.RpcLog.Level.Warning, "Warning: Unexpected call to 'log' on the context object after function execution has completed. Please check for asynchronous calls that are not awaited or calls to 'done' made before function execution completes.");
sinon.assert.calledWith(_logger, rpc.RpcLog.Level.Warning, "Warning: Unexpected call to 'log' on the context object after function execution has completed. Please check for asynchronous calls that are not awaited or calls to 'done' made before function execution completes. Function name: test. Invocation Id: 1.");
});

it ('function calls callback correctly with bindings', () => {
Expand Down

0 comments on commit 86314a8

Please sign in to comment.