-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: append call stack for runInBackground
- Loading branch information
Showing
4 changed files
with
127 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
function prepareObjectStackTrace(_, stack) { | ||
return stack; | ||
} | ||
|
||
export function getCalleeFromStack(withLine: boolean, stackIndex?: number) { | ||
stackIndex = stackIndex === undefined ? 2 : stackIndex; | ||
const limit = Error.stackTraceLimit; | ||
const prep = Error.prepareStackTrace; | ||
|
||
Error.prepareStackTrace = prepareObjectStackTrace; | ||
Error.stackTraceLimit = 5; | ||
|
||
// capture the stack | ||
const obj: any = {}; | ||
Error.captureStackTrace(obj); | ||
let callSite = obj.stack[stackIndex]; | ||
let fileName; | ||
/* istanbul ignore else */ | ||
if (callSite) { | ||
// egg-mock will create a proxy | ||
// https://github.com/eggjs/egg-mock/blob/master/lib/app.js#L174 | ||
fileName = callSite.getFileName(); | ||
/* istanbul ignore if */ | ||
if (fileName && fileName.endsWith('egg-mock/lib/app.js')) { | ||
// TODO: add test | ||
callSite = obj.stack[stackIndex + 1]; | ||
fileName = callSite.getFileName(); | ||
} | ||
} | ||
|
||
Error.prepareStackTrace = prep; | ||
Error.stackTraceLimit = limit; | ||
|
||
/* istanbul ignore if */ | ||
if (!callSite || !fileName) return '<anonymous>'; | ||
if (!withLine) return fileName; | ||
return `${fileName}:${callSite.getLineNumber()}:${callSite.getColumnNumber()}`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { Application, Context } from 'egg'; | ||
import { BackgroundTaskHelper, PrototypeUtil } from '@eggjs/tegg'; | ||
import { EggPrototype } from '@eggjs/tegg-metadata'; | ||
import { TEGG_CONTEXT } from '@eggjs/egg-module-common'; | ||
import { TEggPluginContext } from '../app/extend/context'; | ||
import { getCalleeFromStack } from './Utils'; | ||
|
||
export const LONG_STACK_DELIMITER = '\n --------------------\n'; | ||
|
||
function addLongStackTrace(err: Error, causeError: Error) { | ||
const callSiteStack = causeError.stack; | ||
if (!callSiteStack || typeof callSiteStack !== 'string') { | ||
return; | ||
} | ||
const index = callSiteStack.indexOf('\n'); | ||
if (index !== -1) { | ||
err.stack += LONG_STACK_DELIMITER + callSiteStack.substring(index + 1); | ||
} | ||
} | ||
|
||
export function hijackRunInBackground(app: Application) { | ||
const eggRunInBackground = app.context.runInBackground; | ||
app.context.runInBackground = function runInBackground(this: TEggPluginContext, scope: (ctx: Context) => Promise<any>) { | ||
if (!this[TEGG_CONTEXT]) { | ||
return Reflect.apply(eggRunInBackground, this, [ scope ]); | ||
} | ||
const caseError = new Error('cause'); | ||
let resolveBackgroundTask; | ||
const backgroundTaskPromise = new Promise(resolve => { | ||
resolveBackgroundTask = resolve; | ||
}); | ||
const newScope = async () => { | ||
try { | ||
await scope(this); | ||
} catch (e) { | ||
addLongStackTrace(e, caseError); | ||
throw e; | ||
} finally { | ||
resolveBackgroundTask(); | ||
} | ||
}; | ||
const taskName = (scope as any)._name || scope.name || getCalleeFromStack(true, 2); | ||
(scope as any)._name = taskName; | ||
Object.defineProperty(newScope, 'name', { | ||
value: taskName, | ||
enumerable: false, | ||
configurable: true, | ||
writable: false, | ||
}); | ||
Reflect.apply(eggRunInBackground, this, [ newScope ]); | ||
|
||
const proto = PrototypeUtil.getClazzProto(BackgroundTaskHelper); | ||
const eggObject = app.eggContainerFactory.getEggObject(proto as EggPrototype); | ||
const backgroundTaskHelper = eggObject.obj as BackgroundTaskHelper; | ||
backgroundTaskHelper.run(async () => { | ||
await backgroundTaskPromise; | ||
}); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters