diff --git a/package.json b/package.json index 0230e39..46700e1 100644 --- a/package.json +++ b/package.json @@ -56,8 +56,7 @@ "debug": "~4.3.4", "human-interval": "~2.0.1", "luxon": "^2.3.1", - "mongodb": "^4.3.1", - "get-function-location": "^2.0.0" + "mongodb": "^4.3.1" }, "devDependencies": { "eslint": "^8.11.0", diff --git a/src/Job.ts b/src/Job.ts index 696616a..2be73d0 100644 --- a/src/Job.ts +++ b/src/Job.ts @@ -2,7 +2,6 @@ import * as date from 'date.js'; import * as debug from 'debug'; import { ObjectId } from 'mongodb'; import { fork } from 'child_process'; -import * as getFunctionLocation from 'get-function-location'; import type { Agenda } from './index'; import type { DefinitionProcessor } from './types/JobDefinition'; import { IJobParameters, datefields, TJobDatefield } from './types/JobParameters'; @@ -17,8 +16,6 @@ const log = debug('agenda:job'); export class Job { readonly attrs: IJobParameters; - static functionLocationCache: { [key: string]: string } = {}; - /** this flag is set to true, if a job got canceled (e.g. due to a timeout or other exception), * you can use it for long running tasks to periodically check if canceled is true, * also touch will check if and throws that the job got canceled @@ -362,16 +359,7 @@ export class Job { throw new Error('no forkHelper specified, you need to set a path to a helper script'); } const { forkHelper } = this.agenda; - const location = - Job.functionLocationCache[this.attrs.name] || - (await getFunctionLocation(this.agenda.definitions[this.attrs.name].fn)).source.replace( - /^file:\/\//, - '' - ); - if (!Job.functionLocationCache[this.attrs.name]) { - Job.functionLocationCache[this.attrs.name] = location; - } // console.log('location', location); let controller: AbortController | undefined; let signal: AbortSignal | undefined; @@ -387,7 +375,11 @@ export class Job { const child = fork( forkHelper.path, - [this.attrs.name, this.attrs._id!.toString(), location], + [ + this.attrs.name, + this.attrs._id!.toString(), + this.agenda.definitions[this.attrs.name].filePath || '' + ], { ...forkHelper.options, signal @@ -402,7 +394,7 @@ export class Job { forkHelper, this.attrs.name, this.attrs._id, - location + this.agenda.definitions[this.attrs.name].filePath ); const error = new Error(`child process exited with code: ${code}`); console.warn(error.message); diff --git a/src/index.ts b/src/index.ts index 54b8a76..11d7423 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,6 +14,7 @@ import { JobDbRepository } from './JobDbRepository'; import { JobPriority, parsePriority } from './utils/priority'; import { JobProcessor } from './JobProcessor'; import { calculateProcessEvery } from './utils/processEvery'; +import {getCallerFilePath} from "./utils/stack"; const log = debug('agenda'); @@ -337,8 +338,12 @@ export class Agenda extends EventEmitter { if (this.definitions[name]) { log('overwriting already defined agenda job', name); } - this.definitions[name] = { + + const filePath = getCallerFilePath(); + + this.definitions[name] = { fn: processor, + filePath, concurrency: options?.concurrency || this.attrs.defaultConcurrency, lockLimit: options?.lockLimit || this.attrs.defaultLockLimit, priority: parsePriority(options?.priority), diff --git a/src/types/JobDefinition.ts b/src/types/JobDefinition.ts index 6430b18..4ab45bd 100644 --- a/src/types/JobDefinition.ts +++ b/src/types/JobDefinition.ts @@ -10,6 +10,7 @@ export interface IJobDefinition { /** how many jobs of this kind can run in parallel/simultanously per Agenda instance */ concurrency?: number; + filePath: string | undefined; fn: DefinitionProcessor void)>; } diff --git a/src/utils/stack.ts b/src/utils/stack.ts new file mode 100644 index 0000000..e42b4f0 --- /dev/null +++ b/src/utils/stack.ts @@ -0,0 +1,21 @@ +export function getCallerFilePath(position = 2): string | undefined { + if (position >= Error.stackTraceLimit) { + throw new TypeError( + `getCallerFile(position) requires position be less then Error.stackTraceLimit but position was: \`${position}\` and Error.stackTraceLimit was: \`${Error.stackTraceLimit}\`` + ); + } + + const oldPrepareStackTrace = Error.prepareStackTrace; + Error.prepareStackTrace = (_, stack) => stack; + // eslint-disable-next-line unicorn/error-message + const { stack } = new Error(); + Error.prepareStackTrace = oldPrepareStackTrace; + + if (stack !== null && typeof stack === 'object') { + // stack[0] holds this file + // stack[1] holds where this function was called + // stack[2] holds the file we're interested in + return stack[position] ? (stack[position] as any).getFileName() : undefined; + } + return undefined; +}