@orion-js/dogs 4.6.7 → 4.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/repos/JobsHistoryRepo.ts","../../../node_modules/.bun/rambdax@11.3.1/node_modules/rambdax/src/_internals/isInteger.js","../../../node_modules/.bun/rambdax@11.3.1/node_modules/rambdax/src/_internals/createPath.js","../../../node_modules/.bun/rambdax@11.3.1/node_modules/rambdax/src/_internals/compare.js","../../../node_modules/.bun/rambdax@11.3.1/node_modules/rambdax/src/_internals/includes.js","../../../node_modules/.bun/rambdax@11.3.1/node_modules/rambdax/src/omit.js","../src/types/HistoryRecord.ts","../src/repos/JobsRepo.ts","../src/services/partitions.ts","../src/types/JobRecord.ts","../src/types/StartConfig.ts","../src/schedule.ts","../src/services/EventsService.ts","../src/services/getNextRunDate.ts","../src/services/WorkerService.ts","../src/services/Executor.ts","../src/defineJob/index.ts","../src/service/index.ts"],"sourcesContent":["import {SchemaInAnyOrionForm} from '@orion-js/schema'\nimport {getInstance} from '@orion-js/services'\nimport {JobsHistoryRepo} from './repos/JobsHistoryRepo'\nimport {JobsRepo} from './repos/JobsRepo'\nimport {scheduleJobInternal, scheduleJobsInternal} from './schedule'\nimport {WorkerService} from './services/WorkerService'\nimport {ScheduleJobOptions, ScheduleJobsOptions, ScheduleJobsResult} from './types/Events'\nimport {StartWorkersConfig} from './types/StartConfig'\n\nexport * from './defineJob'\nexport * from './service'\nexport * from './types'\n\nconst workerService = getInstance(WorkerService)\nconst jobsHistoryRepo = getInstance(JobsHistoryRepo)\nconst jobsRepo = getInstance(JobsRepo)\n\nconst startWorkers = (config: StartWorkersConfig) => {\n return workerService.startWorkers(config)\n}\n\n/**\n * @deprecated Use the event job definition.schedule method instead.\n */\nconst scheduleJob = <TParamsSchema extends SchemaInAnyOrionForm = any>(\n options: ScheduleJobOptions<TParamsSchema>,\n) => {\n return scheduleJobInternal(options)\n}\n\n/**\n * Schedule multiple jobs at once for better performance.\n * @deprecated Use the event job definition.scheduleJobs method instead.\n */\nconst scheduleJobs = <TParamsSchema extends SchemaInAnyOrionForm = any>(\n jobs: ScheduleJobsOptions<TParamsSchema>,\n): Promise<ScheduleJobsResult> => {\n return scheduleJobsInternal(jobs)\n}\n\nexport {startWorkers, scheduleJob, scheduleJobs, jobsHistoryRepo, jobsRepo}\n","import {Collection, MongoCollection, Repository, MongoDB} from '@orion-js/mongodb'\nimport {omit} from 'rambdax'\nimport {HistoryRecord, HistoryRecordSchema} from '../types/HistoryRecord'\n\n@Repository()\nexport class JobsHistoryRepo {\n @MongoCollection({\n name: 'orionjs.jobs_dogs_history',\n idGeneration: 'uuid',\n schema: HistoryRecordSchema,\n indexes: [\n {\n keys: {\n jobName: 1,\n startedAt: 1,\n },\n },\n {\n keys: {\n executionId: 1,\n },\n },\n {\n keys: {\n expiresAt: 1,\n },\n options: {\n expireAfterSeconds: 0,\n },\n },\n ],\n })\n history: Collection<HistoryRecord>\n\n async saveExecution(record: MongoDB.WithoutId<HistoryRecord>) {\n await this.history.upsert(\n {executionId: record.executionId},\n {\n $setOnInsert: {\n status: record.status,\n },\n $set: {\n ...omit(['status'], record),\n },\n },\n )\n }\n\n async getExecutions(jobName: string, limit?: number, skip?: number): Promise<HistoryRecord[]> {\n const cursor = this.history.find({jobName}).sort({startedAt: -1})\n\n if (skip) {\n cursor.skip(skip)\n }\n\n if (limit) {\n cursor.limit(limit)\n }\n\n return await cursor.toArray()\n }\n}\n","function _isInteger(n){\n return n << 0 === n\n}\n\nexport const isInteger = Number.isInteger || _isInteger\n\n/**\n * Check if `index` is integer even if it is a string.\n */\nexport const isIndexInteger = index => Number.isInteger(Number(index))\n","import { isInteger } from './isInteger.js'\n\nexport function createPath(path, delimiter = '.'){\n return typeof path === 'string' ?\n path.split(delimiter).map(x => isInteger(x) ? Number(x) : x) :\n path\n}\n","export function compare(a, b){\n return String(a) === String(b)\n}\n","import { compare } from './compare.js'\n\nexport function includes(a, list){\n let index = -1\n const { length } = list\n\n while (++index < length)\n if (compare(list[ index ], a))\n return true\n\n return false\n}\n","import { createPath } from './_internals/createPath.js'\nimport { includes } from './_internals/includes.js'\n\nexport function omit(propsToOmit, obj){\n if (arguments.length === 1) return _obj => omit(propsToOmit, _obj)\n\n if (obj === null || obj === undefined)\n return undefined\n\n const propsToOmitValue = createPath(propsToOmit, ',')\n const willReturn = {}\n\n for (const key in obj)\n if (!includes(key, propsToOmitValue))\n willReturn[ key ] = obj[ key ]\n\n return willReturn\n}\n","import {InferSchemaType, schemaWithName} from '@orion-js/schema'\n\nexport const HistoryRecordSchema = schemaWithName('HistoryRecord', {\n _id: {type: 'string'},\n jobId: {type: 'string'},\n executionId: {type: 'string'},\n jobName: {type: 'string'},\n type: {type: 'string'},\n priority: {type: 'number'},\n tries: {type: 'number'},\n uniqueIdentifier: {type: 'string', optional: true},\n startedAt: {type: 'date'},\n endedAt: {type: 'date'},\n duration: {type: 'number'},\n expiresAt: {type: 'date', optional: true},\n status: {type: 'string', enum: ['success', 'error', 'stale']},\n errorMessage: {type: 'string', optional: true},\n params: {type: 'blackbox', optional: true},\n result: {type: 'any', optional: true},\n})\n\nexport type HistoryRecord = InferSchemaType<typeof HistoryRecordSchema>\n","import {generateId} from '@orion-js/helpers'\nimport {logger} from '@orion-js/logger'\nimport {Collection, MongoCollection, MongoDB, Repository} from '@orion-js/mongodb'\nimport {clean, validate} from '@orion-js/schema'\nimport {getRandomPartition} from '../services/partitions'\nimport {ScheduleJobRecordOptions, ScheduleJobsResult} from '../types/Events'\nimport {JobRecord, JobRecordSchema} from '../types/JobRecord'\nimport {JobDefinitionWithName, RecurrentJobDefinition} from '../types/JobsDefinition'\nimport {DEFAULT_MAX_TRIES_REACHED_RETENTION_MS} from '../types/StartConfig'\nimport {JobToRun} from '../types/Worker'\n\nexport type JobAcquisitionHint = 'byJobName' | 'globalPriority'\n\nexport const JOB_ACQUISITION_HINTS = {\n byJobName: {\n partition: 1,\n jobName: 1,\n priority: -1,\n nextRunAt: 1,\n },\n globalPriority: {\n partition: 1,\n priority: -1,\n nextRunAt: 1,\n },\n} as const satisfies Record<JobAcquisitionHint, MongoDB.IndexSpecification>\n\nexport const INITIAL_JOB_ACQUISITION_HINT = 'byJobName' as const satisfies JobAcquisitionHint\nexport const CANDIDATE_JOB_ACQUISITION_HINT = 'globalPriority' as const satisfies JobAcquisitionHint\n\nconst SORTED_UPDATE_ONE_MIN_WIRE_VERSION = 25\nconst LOCK_ID_INDEX_NAME = 'jobs_dogs_records_lock_id'\nconst PARTITION_JOB_NAME_INDEX_NAME = 'jobs_dogs_records_partition_job_name_priority_next_run'\nconst PARTITION_PRIORITY_INDEX_NAME = 'jobs_dogs_records_partition_priority_next_run'\n\nconst JOB_ACQUISITION_SORT: MongoDB.Sort = {\n priority: -1,\n nextRunAt: 1,\n}\n\nfunction getJobAcquisitionSelector(\n jobNames: string[],\n now: Date,\n partition: number,\n): MongoDB.Filter<JobRecord> {\n return {\n partition,\n jobName: {$in: jobNames},\n nextRunAt: {$lte: now},\n $and: [\n {$or: [{lockedUntil: {$exists: false}}, {lockedUntil: {$lte: now}}]},\n // Exclude event jobs that have reached max tries. Recurrent jobs keep running even\n // if old records still have this status from previous versions.\n {$or: [{type: {$ne: 'event'}}, {status: {$ne: 'maxTriesReached'}}]},\n ],\n }\n}\n\n@Repository()\nexport class JobsRepo {\n @MongoCollection({\n idGeneration: 'uuid',\n name: 'orionjs.jobs_dogs_records',\n schema: JobRecordSchema,\n indexes: [\n {\n keys: JOB_ACQUISITION_HINTS.byJobName,\n options: {name: PARTITION_JOB_NAME_INDEX_NAME},\n },\n {\n keys: JOB_ACQUISITION_HINTS.globalPriority,\n options: {name: PARTITION_PRIORITY_INDEX_NAME},\n },\n {\n keys: {\n jobName: 1,\n },\n options: {\n unique: true,\n partialFilterExpression: {type: 'recurrent'},\n },\n },\n {\n keys: {\n uniqueIdentifier: 1,\n },\n options: {\n unique: true,\n sparse: true,\n },\n },\n {\n keys: {\n lockId: 1,\n },\n options: {\n name: LOCK_ID_INDEX_NAME,\n sparse: true,\n },\n },\n {\n keys: {\n expiresAt: 1,\n },\n name: 'jobs_dogs_records_expires_at_ttl',\n expireAfterSeconds: 0,\n },\n ],\n })\n jobs: Collection<JobRecord>\n\n private sortedUpdateOneSupportPromise?: Promise<boolean>\n private partitionsByJobName = new Map<string, number>()\n\n configureJobPartitions(jobNames: string[], nPartitions: number) {\n for (const jobName of jobNames) {\n this.partitionsByJobName.set(jobName, nPartitions)\n }\n }\n\n getJobPartitionsCount(jobName: string) {\n return this.partitionsByJobName.get(jobName)\n }\n\n async supportsSortedUpdateOne(): Promise<boolean> {\n if (!this.sortedUpdateOneSupportPromise) {\n this.sortedUpdateOneSupportPromise = this.detectSortedUpdateOneSupport()\n }\n\n return this.sortedUpdateOneSupportPromise\n }\n\n private async detectSortedUpdateOneSupport(): Promise<boolean> {\n const rawCollection = await this.jobs.getRawCollection()\n // Both acquisition implementations use explicit hints, so the first claim must wait until the\n // declared indexes are ready even when the server needs the legacy fallback.\n await this.jobs.createIndexesPromise\n const hello = await rawCollection.db.admin().command({hello: 1})\n const supportsSortedUpdateOne =\n typeof hello.maxWireVersion === 'number' &&\n hello.maxWireVersion >= SORTED_UPDATE_ONE_MIN_WIRE_VERSION\n\n if (!supportsSortedUpdateOne) {\n logger.info('MongoDB does not support sorted updateOne; using findOneAndUpdate for jobs.')\n return false\n }\n\n const hasLockIdIndex = await rawCollection.indexExists(LOCK_ID_INDEX_NAME)\n if (!hasLockIdIndex) {\n logger.warn(\n `MongoDB supports sorted updateOne but index \"${LOCK_ID_INDEX_NAME}\" is unavailable; using findOneAndUpdate for jobs.`,\n )\n return false\n }\n\n logger.info('MongoDB supports sorted updateOne; using it for job acquisition.')\n return true\n }\n\n async getJobAndLock(\n jobNames: string[],\n lockTime: number,\n hint: JobAcquisitionHint = INITIAL_JOB_ACQUISITION_HINT,\n partition = 0,\n ): Promise<JobToRun> {\n if (await this.supportsSortedUpdateOne()) {\n return this.getJobAndLockWithSortedUpdateOne(jobNames, lockTime, hint, partition)\n }\n\n return this.getJobAndLockWithFindOneAndUpdate(jobNames, lockTime, hint, partition)\n }\n\n private async getJobAndLockWithFindOneAndUpdate(\n jobNames: string[],\n lockTime: number,\n hint: JobAcquisitionHint,\n partition: number,\n ): Promise<JobToRun> {\n const executionId = generateId()\n const now = new Date()\n const lockedUntil = new Date(now.getTime() + lockTime)\n\n const job = await this.jobs.findOneAndUpdate(\n getJobAcquisitionSelector(jobNames, now, partition),\n {\n $set: {lockId: executionId, lockedUntil, lastRunAt: now},\n $inc: {tries: 1},\n },\n {\n mongoOptions: {\n hint: JOB_ACQUISITION_HINTS[hint],\n sort: JOB_ACQUISITION_SORT,\n returnDocument: 'before',\n },\n },\n )\n\n if (!job) return\n\n const tries = (job.tries || 0) + 1\n const wasStale = Boolean(job.lockedUntil)\n\n return this.toJobToRun(job, executionId, lockTime, tries, wasStale)\n }\n\n private async getJobAndLockWithSortedUpdateOne(\n jobNames: string[],\n lockTime: number,\n hint: JobAcquisitionHint,\n partition: number,\n ): Promise<JobToRun> {\n const executionId = generateId()\n const now = new Date()\n const lockedUntil = new Date(now.getTime() + lockTime)\n const rawCollection = await this.jobs.getRawCollection()\n\n const result = await rawCollection.updateOne(\n getJobAcquisitionSelector(jobNames, now, partition),\n [\n {\n $set: {\n lockId: {$literal: executionId},\n lockedUntil: {$literal: lockedUntil},\n lastRunAt: {$literal: now},\n tries: {$add: [{$ifNull: ['$tries', 0]}, 1]},\n claimWasStale: {$eq: [{$type: '$lockedUntil'}, 'date']},\n },\n },\n ],\n {\n hint: JOB_ACQUISITION_HINTS[hint],\n sort: JOB_ACQUISITION_SORT,\n },\n )\n\n if (result.matchedCount === 0) return\n\n const job = await rawCollection.findOne({lockId: executionId})\n if (!job) return\n\n return this.toJobToRun(job, executionId, lockTime, job.tries || 0, Boolean(job.claimWasStale))\n }\n\n private toJobToRun(\n job: JobRecord,\n executionId: string,\n lockTime: number,\n tries: number,\n wasStale: boolean,\n ): JobToRun {\n if (wasStale) {\n logger.info(`Running job \"${job.jobName}\" that was staled`)\n }\n\n return {\n jobId: job._id,\n executionId,\n lockId: executionId,\n name: job.jobName,\n params: job.params,\n type: job.type,\n tries,\n lockTime,\n priority: job.priority,\n uniqueIdentifier: job.uniqueIdentifier,\n wasStale,\n }\n }\n\n async getJobAcquisitionExecutionTime(\n jobNames: string[],\n hint: JobAcquisitionHint,\n partition = 0,\n ): Promise<number> {\n const explain = await this.jobs\n .find(getJobAcquisitionSelector(jobNames, new Date(), partition), {\n hint: JOB_ACQUISITION_HINTS[hint],\n maxTimeMS: 1000,\n readPreference: 'primary',\n })\n .sort(JOB_ACQUISITION_SORT)\n .limit(1)\n .explain('executionStats')\n\n const executionTimeMillis = explain.executionStats?.executionTimeMillis\n if (typeof executionTimeMillis !== 'number' || !Number.isFinite(executionTimeMillis)) {\n throw new Error(`Explain for acquisition hint \"${hint}\" returned no execution time`)\n }\n\n return executionTimeMillis\n }\n\n async setJobRecordPriority(jobId: string, priority: number, lockId?: string) {\n const result = await this.jobs.updateOne(lockId ? {_id: jobId, lockId} : jobId, {\n $set: {priority},\n })\n return result.matchedCount > 0\n }\n\n async scheduleNextRun(options: {\n jobId: string\n nextRunAt: Date\n resetTries: boolean\n priority: number\n lockId?: string\n }) {\n const updator: MongoDB.UpdateFilter<JobRecord> = {\n $set: {\n nextRunAt: options.nextRunAt,\n priority: options.priority,\n ...(options.resetTries ? {tries: 0} : {}),\n },\n $unset: {lockId: '', lockedUntil: '', claimWasStale: ''},\n }\n\n const result = await this.jobs.updateOne(\n options.lockId ? {_id: options.jobId, lockId: options.lockId} : options.jobId,\n updator,\n )\n return result.matchedCount > 0\n }\n\n async deleteEventJob(jobId: string, lockId?: string) {\n const result = await this.jobs.deleteOne({\n _id: jobId,\n type: 'event',\n ...(lockId ? {lockId} : {}),\n })\n return result.deletedCount > 0\n }\n\n /**\n * Marks an event job as having reached its maximum tries limit.\n * The job won't be picked up for execution and MongoDB will delete it after\n * the configured retention period.\n */\n async markJobAsMaxTriesReached(\n jobId: string,\n retentionMs: number | null = DEFAULT_MAX_TRIES_REACHED_RETENTION_MS,\n lockId?: string,\n ) {\n const maxTriesReachedAt = new Date()\n const result = await this.jobs.updateOne(\n {_id: jobId, type: 'event', ...(lockId ? {lockId} : {})},\n {\n $set: {\n status: 'maxTriesReached',\n maxTriesReachedAt,\n ...(retentionMs === null\n ? {}\n : {expiresAt: new Date(maxTriesReachedAt.getTime() + retentionMs)}),\n },\n $unset: {\n lockId: '',\n lockedUntil: '',\n claimWasStale: '',\n ...(retentionMs === null ? {expiresAt: ''} : {}),\n },\n },\n )\n return result.matchedCount > 0\n }\n\n /**\n * Applies the current retention configuration to existing maxTriesReached\n * event jobs. The collection definition ensures the TTL index. Legacy records\n * use lastRunAt as their retention anchor when available.\n */\n async ensureMaxTriesReachedRetention(retentionMs: number | null) {\n const selector = {\n type: 'event' as const,\n status: 'maxTriesReached' as const,\n }\n\n if (retentionMs === null) {\n await this.jobs.updateMany(selector, {$unset: {expiresAt: ''}})\n return\n }\n\n const now = new Date()\n const retentionAnchor = {\n $ifNull: ['$maxTriesReachedAt', {$ifNull: ['$lastRunAt', now]}],\n }\n\n await this.jobs.rawCollection.updateMany(selector, [\n {\n $set: {\n maxTriesReachedAt: retentionAnchor,\n expiresAt: {$add: [retentionAnchor, retentionMs]},\n },\n },\n ])\n }\n\n async extendLockTime(jobId: string, extraTime: number, lockId?: string) {\n return this.updateLockTime(jobId, extraTime, lockId)\n }\n\n /**\n * Updates the lock time for a job to the specified duration from now.\n * Can be used to both extend or shorten the lock time.\n */\n async updateLockTime(jobId: string, lockDuration: number, lockId?: string) {\n const lockedUntil = new Date(Date.now() + lockDuration)\n const result = await this.jobs.updateOne(\n {_id: jobId, ...(lockId ? {lockId} : {})},\n {\n $set: {lockedUntil},\n },\n )\n return result.matchedCount > 0\n }\n\n async unlockAllJobs(): Promise<number> {\n const result = await this.jobs.updateMany(\n {\n lockedUntil: {$exists: true},\n },\n {\n $unset: {lockId: '', lockedUntil: '', claimWasStale: ''},\n },\n )\n\n return result.modifiedCount\n }\n\n async ensureJobRecord(job: JobDefinitionWithName, partition = 0) {\n const result = await this.jobs.upsert(\n {\n jobName: job.name,\n },\n {\n $set: {\n type: job.type,\n priority: (job as RecurrentJobDefinition).priority,\n },\n $unset: {\n status: '',\n },\n $setOnInsert: {\n nextRunAt: new Date(),\n partition,\n },\n },\n )\n\n if (result.upsertedId) {\n logger.debug(`Created job record for \"${job.name}\"`)\n } else {\n logger.debug(`Record for job \"${job.name}\" already exists`)\n }\n }\n\n async scheduleJob(options: ScheduleJobRecordOptions) {\n try {\n await this.jobs.insertOne({\n jobName: options.name,\n uniqueIdentifier: options.uniqueIdentifier,\n params: options.params,\n nextRunAt: options.nextRunAt,\n priority: options.priority,\n type: 'event',\n ...(options.partition === undefined ? {} : {partition: options.partition}),\n })\n } catch (error) {\n if (\n error.isValidationError &&\n Object.values(error.validationErrors).includes('notUnique') &&\n options.uniqueIdentifier\n ) {\n logger.info(\n `Job \"${options.name}\" with identifier \"${options.uniqueIdentifier}\" already exists`,\n )\n } else {\n throw error\n }\n }\n }\n\n async scheduleJobs(jobs: ScheduleJobRecordOptions[]): Promise<ScheduleJobsResult> {\n if (jobs.length === 0) {\n return {scheduledCount: 0, skippedCount: 0, errors: []}\n }\n\n const errors: Array<{index: number; error: Error; job: ScheduleJobRecordOptions}> = []\n const preparedJobs: Array<{\n index: number\n job: ScheduleJobRecordOptions\n record: JobRecord\n }> = []\n\n for (let i = 0; i < jobs.length; i++) {\n const job = jobs[i]\n try {\n const record = (await clean(JobRecordSchema, {\n _id: this.jobs.generateId(),\n jobName: job.name,\n uniqueIdentifier: job.uniqueIdentifier,\n params: job.params,\n nextRunAt: job.nextRunAt,\n priority: job.priority,\n type: 'event',\n ...(job.partition === undefined ? {} : {partition: job.partition}),\n })) as JobRecord\n await validate(JobRecordSchema, record)\n preparedJobs.push({index: i, job, record})\n } catch (error) {\n errors.push({\n index: i,\n error: error instanceof Error ? error : new Error(String(error)),\n job,\n })\n }\n }\n\n if (preparedJobs.length === 0) {\n return {scheduledCount: 0, skippedCount: 0, errors}\n }\n\n const rawCollection = await this.jobs.getRawCollection()\n await this.jobs.createIndexesPromise\n const operations: MongoDB.AnyBulkWriteOperation<JobRecord>[] = preparedJobs.map(({record}) =>\n record.uniqueIdentifier === undefined\n ? {insertOne: {document: record}}\n : {\n updateOne: {\n filter: {uniqueIdentifier: record.uniqueIdentifier},\n update: {$setOnInsert: record},\n upsert: true,\n },\n },\n )\n\n let scheduledCount = 0\n let skippedCount = 0\n\n try {\n const result = await rawCollection.bulkWrite(operations, {ordered: false})\n scheduledCount = result.insertedCount + result.upsertedCount\n skippedCount = result.matchedCount\n } catch (error) {\n const writeErrors =\n error instanceof MongoDB.MongoBulkWriteError\n ? Array.isArray(error.writeErrors)\n ? error.writeErrors\n : [error.writeErrors]\n : []\n\n if (!(error instanceof MongoDB.MongoBulkWriteError) || writeErrors.length === 0) {\n for (const preparedJob of preparedJobs) {\n errors.push({\n index: preparedJob.index,\n error: error instanceof Error ? error : new Error(String(error)),\n job: preparedJob.job,\n })\n }\n } else {\n scheduledCount = error.result.insertedCount + error.result.upsertedCount\n skippedCount = error.result.matchedCount\n\n for (const writeError of writeErrors) {\n const preparedJob = preparedJobs[writeError.index]\n if (!preparedJob) continue\n\n if (writeError.code === 11000 && preparedJob.record.uniqueIdentifier !== undefined) {\n skippedCount++\n continue\n }\n\n errors.push({\n index: preparedJob.index,\n error: new Error(writeError.errmsg),\n job: preparedJob.job,\n })\n }\n }\n }\n\n logger.debug(\n `Scheduled ${scheduledCount} jobs successfully, skipped ${skippedCount}, errors: ${errors.length}`,\n )\n\n return {\n scheduledCount,\n skippedCount,\n errors,\n }\n }\n\n async reconcilePartitions(options: {\n jobNames: string[]\n nPartitions: number\n batchSize: number\n }): Promise<number> {\n if (options.jobNames.length === 0) return 0\n\n const rawCollection = await this.jobs.getRawCollection()\n await this.jobs.createIndexesPromise\n const now = new Date()\n const invalidPartition: MongoDB.Filter<JobRecord> = {\n $or: [\n {partition: {$exists: false}},\n {partition: {$lt: 0}},\n {partition: {$gte: options.nPartitions}},\n ],\n }\n const availableLock: MongoDB.Filter<JobRecord> = {\n $or: [{lockedUntil: {$exists: false}}, {lockedUntil: {$lte: now}}],\n }\n const runnableJob: MongoDB.Filter<JobRecord> = {\n $or: [{type: {$ne: 'event'}}, {status: {$ne: 'maxTriesReached'}}],\n }\n\n const jobs = await rawCollection\n .find({\n jobName: {$in: options.jobNames},\n $and: [invalidPartition, availableLock, runnableJob],\n })\n .project({_id: 1})\n .limit(options.batchSize)\n .toArray()\n\n if (jobs.length === 0) return 0\n\n const result = await rawCollection.bulkWrite(\n jobs.map(job => ({\n updateOne: {\n filter: {\n _id: job._id,\n $and: [invalidPartition, availableLock, runnableJob],\n },\n update: {$set: {partition: getRandomPartition(options.nPartitions)}},\n },\n })),\n {ordered: false},\n )\n\n return result.modifiedCount\n }\n}\n","export function validatePartitionsCount(nPartitions: number) {\n if (!Number.isInteger(nPartitions) || nPartitions <= 0) {\n throw new Error('nPartitions must be a positive integer')\n }\n}\n\nexport function getRandomPartition(nPartitions: number) {\n return Math.floor(Math.random() * nPartitions)\n}\n\nexport function createShuffledPartitions(nPartitions: number) {\n const partitions = Array.from({length: nPartitions}, (_, partition) => partition)\n\n for (let index = partitions.length - 1; index > 0; index--) {\n const swapIndex = Math.floor(Math.random() * (index + 1))\n ;[partitions[index], partitions[swapIndex]] = [partitions[swapIndex], partitions[index]]\n }\n\n return partitions\n}\n","import {createEnum, InferSchemaType, schemaWithName} from '@orion-js/schema'\n\n/**\n * Enum representing the status of a job record.\n * - 'pending': Job is active and can be executed (default for existing records)\n * - 'maxTriesReached': Event job has exhausted all retry attempts and won't be executed\n */\nexport const JobStatusEnum = createEnum('JobStatus', ['pending', 'maxTriesReached'])\n\nexport const JobRecordSchema = schemaWithName('JobRecord', {\n _id: {type: 'string'},\n jobName: {type: 'string'},\n type: {type: createEnum('JobType', ['recurrent', 'event'])},\n priority: {type: 'number'},\n uniqueIdentifier: {type: 'string', optional: true},\n nextRunAt: {type: 'date'},\n /**\n * Acquisition partition. Optional so records created by previous versions can be reconciled.\n */\n partition: {type: 'number', optional: true},\n lastRunAt: {type: 'date', optional: true},\n lockedUntil: {type: 'date', optional: true},\n /**\n * Identifies the execution that currently owns the lock. Mutations from an execution must match\n * this value so a stale execution cannot modify a newer claim.\n */\n lockId: {type: 'string', optional: true},\n /**\n * Internal acquisition metadata used when MongoDB supports sorted updateOne. It preserves the\n * pre-update stale state because updateOne intentionally does not return the previous document.\n */\n claimWasStale: {type: 'boolean', optional: true},\n tries: {type: 'number', optional: true},\n params: {type: 'blackbox', optional: true},\n /**\n * Status of the job. Optional for backwards compatibility with existing records.\n * Records without this field are treated as 'pending'.\n */\n status: {type: JobStatusEnum, optional: true},\n /**\n * Date when the job reached its maximum tries. Used as the stable anchor when\n * maxTriesReachedRetentionMs changes between worker restarts.\n */\n maxTriesReachedAt: {type: 'date', optional: true},\n /**\n * Date when MongoDB should remove a terminal event job through the TTL index.\n */\n expiresAt: {type: 'date', optional: true},\n})\n\nexport type JobRecord = InferSchemaType<typeof JobRecordSchema>\n","import {JobsDefinition} from './JobsDefinition'\nimport {JobToRun} from './Worker'\n\nexport type LogLevels = 'debug' | 'info' | 'warn' | 'error' | 'none'\n\nexport const DEFAULT_MAX_TRIES_REACHED_RETENTION_MS = 1000 * 60 * 60 * 24 * 7\n\nexport interface StartWorkersConfig {\n /**\n * Object map of the jobs that this scheduler will execute.\n */\n jobs: JobsDefinition\n /**\n * Maximum number of tries for an event job before it is marked as 'maxTriesReached'.\n * This is a global default that can be overridden per event job definition.\n */\n maxTries?: number\n /**\n * Time in milliseconds to keep event jobs after they reach their maximum tries.\n * Defaults to one week. Set to null to keep them indefinitely.\n */\n maxTriesReachedRetentionMs?: number | null\n /**\n * Callback invoked when an event job reaches its maximum tries limit.\n * Use this to notify administrators (e.g., send an email alert).\n * The job will remain in the database with status 'maxTriesReached' until its\n * configured retention period expires.\n */\n onMaxTriesReached?: (job: JobToRun) => Promise<void>\n /**\n * Time in milliseconds to wait between each look without results for a job\n * to run at the database. Default is 3000.\n */\n pollInterval?: number\n /**\n * @deprecated The centralized scheduler no longer waits after successful job acquisition or\n * execution. This option is accepted for backwards compatibility and ignored.\n */\n cooldownPeriod?: number\n /**\n * Maximum number of concurrent job executions for this scheduler. Default is 4.\n */\n workersCount?: number\n /**\n * Number of database partitions used to spread job acquisition contention.\n * Each claim queries exactly one partition. Default is 1.\n */\n nPartitions?: number\n /**\n * Default time in milliseconds to lock a job for execution. Default is 30000 (30 seconds).\n * If a job is locked for longer than this time, it will be considered as failed.\n * This is to prevent a job from being executed multiple times at the same time.\n * You can extend this time inside a job by calling extendLockTime from context.\n * Individual jobs can override this value by setting their own lockTime.\n */\n defaultLockTime?: number\n}\n","import {SchemaInAnyOrionForm} from '@orion-js/schema'\nimport {getInstance} from '@orion-js/services'\nimport {EventsService} from './services/EventsService'\nimport {ScheduleJobOptions, ScheduleJobsOptions, ScheduleJobsResult} from './types/Events'\n\nconst eventsService = getInstance(EventsService)\n\nexport function scheduleJobInternal<TParamsSchema extends SchemaInAnyOrionForm = any>(\n options: ScheduleJobOptions<TParamsSchema>,\n nPartitions?: number,\n) {\n return eventsService.scheduleJob(options, nPartitions)\n}\n\nexport function scheduleJobsInternal<TParamsSchema extends SchemaInAnyOrionForm = any>(\n jobs: ScheduleJobsOptions<TParamsSchema>,\n nPartitions?: number,\n): Promise<ScheduleJobsResult> {\n return eventsService.scheduleJobs(jobs, nPartitions)\n}\n","import {logger} from '@orion-js/logger'\nimport {Inject, Service} from '@orion-js/services'\nimport {JobsRepo} from '../repos/JobsRepo'\nimport {ScheduleJobOptions, ScheduleJobsOptions, ScheduleJobsResult} from '../types/Events'\nimport {getNextRunDate} from './getNextRunDate'\nimport {getRandomPartition} from './partitions'\n\n@Service()\nexport class EventsService {\n @Inject(() => JobsRepo)\n private jobsRepo: JobsRepo\n\n async scheduleJob(options: ScheduleJobOptions, nPartitions?: number) {\n logger.debug('Scheduling job...', options)\n const configuredPartitions = nPartitions ?? this.jobsRepo.getJobPartitionsCount(options.name)\n\n await this.jobsRepo.scheduleJob({\n name: options.name,\n priority: options.priority || 100,\n nextRunAt: getNextRunDate(options),\n params: options.params || null,\n uniqueIdentifier: options.uniqueIdentifier,\n partition:\n configuredPartitions === undefined ? undefined : getRandomPartition(configuredPartitions),\n })\n }\n\n async scheduleJobs(jobs: ScheduleJobsOptions, nPartitions?: number): Promise<ScheduleJobsResult> {\n logger.debug(`Scheduling ${jobs.length} jobs...`)\n\n const jobRecords = jobs.map(options => {\n const configuredPartitions = nPartitions ?? this.jobsRepo.getJobPartitionsCount(options.name)\n return {\n name: options.name,\n priority: options.priority || 100,\n nextRunAt: getNextRunDate(options),\n params: options.params || null,\n uniqueIdentifier: options.uniqueIdentifier,\n partition:\n configuredPartitions === undefined ? undefined : getRandomPartition(configuredPartitions),\n }\n })\n\n return await this.jobsRepo.scheduleJobs(jobRecords)\n }\n}\n","import {CronExpressionParser} from 'cron-parser'\n\nexport type Options = {\n getNextRun?: () => Date\n runIn?: number\n runEvery?: number\n runAt?: Date\n cron?: string\n timezone?: string\n currentDate?: Date | string | number\n} & {[key: string]: any}\n\nexport const getNextRunDate = (options: Options) => {\n if (options.runIn) {\n return new Date(Date.now() + options.runIn)\n }\n\n if (options.runEvery) {\n return new Date(Date.now() + options.runEvery)\n }\n\n if (options.cron) {\n if (!options.timezone) {\n throw new Error('Cron recurrent jobs require a timezone')\n }\n\n return CronExpressionParser.parse(options.cron, {\n currentDate: options.currentDate ?? new Date(),\n tz: options.timezone,\n })\n .next()\n .toDate()\n }\n\n if (options.runAt) {\n return options.runAt\n }\n\n if (options.getNextRun) {\n return options.getNextRun()\n }\n\n return new Date()\n}\n","import {sleep} from '@orion-js/helpers'\nimport {logger} from '@orion-js/logger'\nimport {Inject, Service} from '@orion-js/services'\nimport {\n CANDIDATE_JOB_ACQUISITION_HINT,\n INITIAL_JOB_ACQUISITION_HINT,\n JobAcquisitionHint,\n JobsRepo,\n} from '../repos/JobsRepo'\nimport {JobDefinitionWithName, JobsDefinition} from '../types/JobsDefinition'\nimport {DEFAULT_MAX_TRIES_REACHED_RETENTION_MS, StartWorkersConfig} from '../types/StartConfig'\nimport {JobToRun, WorkersInstance} from '../types/Worker'\nimport {ExecuteJobConfig, Executor} from './Executor'\nimport {createShuffledPartitions, getRandomPartition, validatePartitionsCount} from './partitions'\n\nconst FILTERED_JOB_NAMES_ACQUISITION_HINT = 'byJobName' as const satisfies JobAcquisitionHint\n\ninterface TrackedExecution {\n job: JobToRun\n promise: Promise<void>\n capacityPromise: Promise<void>\n releaseCapacity: () => void\n status: 'running' | 'stale' | 'finished'\n}\n\ninterface InternalWorkersInstance extends WorkersInstance {\n activeExecutions: Map<string, TrackedExecution>\n staleExecutions: Map<string, TrackedExecution>\n runningJobsByName: Map<string, number>\n jobAcquisitionHint: JobAcquisitionHint\n jobAcquisitionHintProbeCycle: number\n hasCompletedInitialJobAcquisitionHintProbe: boolean\n pendingJobAcquisitionHint?: JobAcquisitionHint\n pendingJobAcquisitionHintWins: number\n jobAcquisitionHintProbePromise: Promise<void>\n jobAcquisitionHintProbeTimer?: ReturnType<typeof setTimeout>\n cancelJobAcquisitionHintProbeWait?: () => void\n partitionOrder: number[]\n partitionCursor: number\n partitionReconcilerPromise: Promise<void>\n partitionReconcilerTimer?: ReturnType<typeof setTimeout>\n cancelPartitionReconcilerWait?: () => void\n schedulerPromise: Promise<void>\n stopSignal: Promise<void>\n signalStop: () => void\n stopPromise?: Promise<void>\n}\n\n@Service()\nexport class WorkerService {\n private jobAcquisitionHintProbeIntervalMs = 30 * 60 * 1000\n private partitionReconcilerIntervalMs = 5 * 60 * 1000\n private partitionReconcilerJitterMs = 30 * 1000\n private partitionReconcilerBatchPauseMs = 250\n private partitionReconcilerBatchSize = 500\n\n @Inject(() => JobsRepo)\n private jobsRepo: JobsRepo\n\n @Inject(() => Executor)\n private executor: Executor\n\n getJobNames(jobs: JobsDefinition) {\n return Object.keys(jobs)\n }\n\n getJobs(jobs: JobsDefinition): JobDefinitionWithName[] {\n return Object.keys(jobs).map(name => {\n return {\n name,\n ...jobs[name],\n }\n })\n }\n\n getAvailableJobNames(\n config: StartWorkersConfig,\n workersInstance: InternalWorkersInstance,\n jobNames: string[],\n ) {\n return jobNames.filter(jobName => {\n const currentExecutions = workersInstance.runningJobsByName.get(jobName) || 0\n const job = config.jobs[jobName]\n const maxParallelExecutions =\n job.type === 'event'\n ? (job.maxParallelExecutionsPerServer ?? Number.POSITIVE_INFINITY)\n : Number.POSITIVE_INFINITY\n\n return currentExecutions < maxParallelExecutions\n })\n }\n\n reserveJobExecution(workersInstance: InternalWorkersInstance, jobName: string) {\n const currentExecutions = workersInstance.runningJobsByName.get(jobName) || 0\n workersInstance.runningJobsByName.set(jobName, currentExecutions + 1)\n }\n\n releaseJobExecution(workersInstance: InternalWorkersInstance, jobName: string) {\n const currentExecutions = workersInstance.runningJobsByName.get(jobName) || 0\n if (currentExecutions <= 1) {\n workersInstance.runningJobsByName.delete(jobName)\n return\n }\n\n workersInstance.runningJobsByName.set(jobName, currentExecutions - 1)\n }\n\n releaseExecutionCapacity(\n workersInstance: InternalWorkersInstance,\n execution: TrackedExecution,\n nextStatus: 'stale' | 'finished',\n ) {\n if (execution.status !== 'running') return\n\n execution.status = nextStatus\n workersInstance.activeExecutions.delete(execution.job.executionId)\n this.releaseJobExecution(workersInstance, execution.job.name)\n execution.releaseCapacity()\n\n if (nextStatus === 'stale') {\n workersInstance.staleExecutions.set(execution.job.executionId, execution)\n }\n }\n\n startExecution(\n config: ExecuteJobConfig,\n workersInstance: InternalWorkersInstance,\n jobToRun: JobToRun,\n ) {\n let releaseCapacity!: () => void\n const capacityPromise = new Promise<void>(resolve => {\n releaseCapacity = resolve\n })\n\n const execution: TrackedExecution = {\n job: jobToRun,\n promise: Promise.resolve(),\n capacityPromise,\n releaseCapacity,\n status: 'running',\n }\n\n this.reserveJobExecution(workersInstance, jobToRun.name)\n workersInstance.activeExecutions.set(jobToRun.executionId, execution)\n\n logger.debug(`Starting job execution \"${jobToRun.executionId}\"`, jobToRun)\n\n const executionPromise = this.executor.executeJob(config, jobToRun, () => {\n this.releaseExecutionCapacity(workersInstance, execution, 'stale')\n })\n execution.promise = executionPromise\n\n void executionPromise\n .catch(error => {\n logger.error(`Unhandled error executing job \"${jobToRun.name}\"`, {error})\n })\n .finally(() => {\n if (execution.status === 'running') {\n this.releaseExecutionCapacity(workersInstance, execution, 'finished')\n } else if (execution.status === 'stale') {\n workersInstance.staleExecutions.delete(jobToRun.executionId)\n }\n })\n }\n\n async waitForPollOrStop(config: StartWorkersConfig, workersInstance: InternalWorkersInstance) {\n await Promise.race([sleep(config.pollInterval), workersInstance.stopSignal])\n }\n\n async waitForCapacityOrStop(workersInstance: InternalWorkersInstance) {\n const capacityPromises = Array.from(\n workersInstance.activeExecutions.values(),\n execution => execution.capacityPromise,\n )\n\n if (capacityPromises.length === 0) return\n await Promise.race([...capacityPromises, workersInstance.stopSignal])\n }\n\n getNextPartition(config: StartWorkersConfig, workersInstance: InternalWorkersInstance) {\n const partition = workersInstance.partitionOrder[workersInstance.partitionCursor]\n workersInstance.partitionCursor++\n\n if (workersInstance.partitionCursor >= config.nPartitions) {\n workersInstance.partitionOrder = createShuffledPartitions(config.nPartitions)\n workersInstance.partitionCursor = 0\n }\n\n return partition\n }\n\n async runSchedulerLoop(config: StartWorkersConfig, workersInstance: InternalWorkersInstance) {\n const jobNames = this.getJobNames(config.jobs)\n const executeConfig: ExecuteJobConfig = {\n jobs: config.jobs,\n maxTries: config.maxTries,\n maxTriesReachedRetentionMs: config.maxTriesReachedRetentionMs,\n onMaxTriesReached: config.onMaxTriesReached,\n }\n\n logger.debug(`Running scheduler loop for jobs \"${jobNames.join(', ')}\"...`)\n let consecutivePartitionMisses = 0\n\n while (workersInstance.running) {\n let didMiss = false\n let allJobNamesAtCapacity = false\n\n try {\n while (workersInstance.activeExecutions.size < config.workersCount) {\n const availableJobNames = this.getAvailableJobNames(config, workersInstance, jobNames)\n\n if (availableJobNames.length === 0) {\n allJobNamesAtCapacity = workersInstance.activeExecutions.size > 0\n break\n }\n\n const jobAcquisitionHint =\n availableJobNames.length < jobNames.length\n ? FILTERED_JOB_NAMES_ACQUISITION_HINT\n : workersInstance.jobAcquisitionHint\n const partition = this.getNextPartition(config, workersInstance)\n const jobToRun = await this.jobsRepo.getJobAndLock(\n availableJobNames,\n config.defaultLockTime,\n jobAcquisitionHint,\n partition,\n )\n\n if (!jobToRun) {\n consecutivePartitionMisses++\n logger.debug(`No job to run in partition ${partition}`)\n if (consecutivePartitionMisses >= config.nPartitions) {\n consecutivePartitionMisses = 0\n didMiss = true\n break\n }\n continue\n }\n\n consecutivePartitionMisses = 0\n // An acquisition already in flight when stop() is called is considered committed.\n this.startExecution(executeConfig, workersInstance, jobToRun)\n if (!workersInstance.running) break\n }\n } catch (error) {\n logger.error('Error in job scheduler.', {error})\n consecutivePartitionMisses = 0\n didMiss = true\n }\n\n if (!workersInstance.running) return\n\n const concurrencyIsFull =\n workersInstance.activeExecutions.size >= config.workersCount &&\n workersInstance.activeExecutions.size > 0\n\n if (concurrencyIsFull || allJobNamesAtCapacity) {\n await this.waitForCapacityOrStop(workersInstance)\n } else if (didMiss || workersInstance.activeExecutions.size === 0) {\n await this.waitForPollOrStop(config, workersInstance)\n }\n }\n }\n\n getOtherJobAcquisitionHint(hint: JobAcquisitionHint): JobAcquisitionHint {\n return hint === INITIAL_JOB_ACQUISITION_HINT\n ? CANDIDATE_JOB_ACQUISITION_HINT\n : INITIAL_JOB_ACQUISITION_HINT\n }\n\n getMedian(values: number[]): number {\n const sortedValues = [...values].sort((left, right) => left - right)\n return sortedValues[Math.floor(sortedValues.length / 2)]\n }\n\n resetPendingJobAcquisitionHint(workersInstance: InternalWorkersInstance) {\n workersInstance.pendingJobAcquisitionHint = undefined\n workersInstance.pendingJobAcquisitionHintWins = 0\n }\n\n async runJobAcquisitionHintProbe(\n config: StartWorkersConfig,\n workersInstance: InternalWorkersInstance,\n ) {\n const jobNames = this.getJobNames(config.jobs)\n if (jobNames.length === 0 || !workersInstance.running) return\n\n const byHint: Record<JobAcquisitionHint, number[]> = {\n [INITIAL_JOB_ACQUISITION_HINT]: [],\n [CANDIDATE_JOB_ACQUISITION_HINT]: [],\n }\n const startsWithInitialHint = workersInstance.jobAcquisitionHintProbeCycle % 2 === 0\n const firstHint = startsWithInitialHint\n ? INITIAL_JOB_ACQUISITION_HINT\n : CANDIDATE_JOB_ACQUISITION_HINT\n const secondHint = this.getOtherJobAcquisitionHint(firstHint)\n workersInstance.jobAcquisitionHintProbeCycle++\n\n try {\n for (let sample = 0; sample < 3; sample++) {\n const partition = getRandomPartition(config.nPartitions)\n for (const hint of [firstHint, secondHint]) {\n if (!workersInstance.running) return\n const executionTimeMillis = await this.jobsRepo.getJobAcquisitionExecutionTime(\n jobNames,\n hint,\n partition,\n )\n if (!workersInstance.running) return\n byHint[hint].push(executionTimeMillis)\n }\n }\n } catch (error) {\n this.resetPendingJobAcquisitionHint(workersInstance)\n if (workersInstance.running) {\n logger.warn('Job acquisition hint probe failed; keeping the current hint.', {error})\n }\n return\n }\n\n const currentHint = workersInstance.jobAcquisitionHint\n const otherHint = this.getOtherJobAcquisitionHint(currentHint)\n const currentMedian = this.getMedian(byHint[currentHint])\n const otherMedian = this.getMedian(byHint[otherHint])\n const winner = otherMedian < currentMedian ? otherHint : currentHint\n\n if (!workersInstance.hasCompletedInitialJobAcquisitionHintProbe) {\n workersInstance.hasCompletedInitialJobAcquisitionHintProbe = true\n workersInstance.jobAcquisitionHint = winner\n this.resetPendingJobAcquisitionHint(workersInstance)\n logger.info(`Selected job acquisition hint \"${winner}\" after startup probe.`)\n return\n }\n\n if (winner === currentHint) {\n this.resetPendingJobAcquisitionHint(workersInstance)\n logger.debug(`Keeping job acquisition hint \"${currentHint}\" after probe.`)\n return\n }\n\n if (workersInstance.pendingJobAcquisitionHint === winner) {\n workersInstance.pendingJobAcquisitionHintWins++\n } else {\n workersInstance.pendingJobAcquisitionHint = winner\n workersInstance.pendingJobAcquisitionHintWins = 1\n }\n\n if (workersInstance.pendingJobAcquisitionHintWins < 2) {\n logger.debug(\n `Keeping job acquisition hint \"${currentHint}\"; \"${winner}\" has one consecutive probe win.`,\n )\n return\n }\n\n workersInstance.jobAcquisitionHint = winner\n this.resetPendingJobAcquisitionHint(workersInstance)\n logger.info(`Changed job acquisition hint from \"${currentHint}\" to \"${winner}\".`)\n }\n\n async waitForNextJobAcquisitionHintProbe(workersInstance: InternalWorkersInstance) {\n await new Promise<void>(resolve => {\n let resolved = false\n const finishWait = () => {\n if (resolved) return\n resolved = true\n clearTimeout(workersInstance.jobAcquisitionHintProbeTimer)\n workersInstance.jobAcquisitionHintProbeTimer = undefined\n workersInstance.cancelJobAcquisitionHintProbeWait = undefined\n resolve()\n }\n\n workersInstance.jobAcquisitionHintProbeTimer = setTimeout(\n finishWait,\n this.jobAcquisitionHintProbeIntervalMs,\n )\n workersInstance.cancelJobAcquisitionHintProbeWait = finishWait\n })\n }\n\n async runJobAcquisitionHintProbeLoop(\n config: StartWorkersConfig,\n workersInstance: InternalWorkersInstance,\n ) {\n if (this.getJobNames(config.jobs).length === 0) return\n\n while (workersInstance.running) {\n await this.runJobAcquisitionHintProbe(config, workersInstance)\n if (!workersInstance.running) return\n await this.waitForNextJobAcquisitionHintProbe(workersInstance)\n }\n }\n\n async reconcilePartitionBatch(config: StartWorkersConfig) {\n // Some embedders replace the repository in isolated scheduler tests.\n if (typeof this.jobsRepo.reconcilePartitions !== 'function') return 0\n\n try {\n return await this.jobsRepo.reconcilePartitions({\n jobNames: this.getJobNames(config.jobs),\n nPartitions: config.nPartitions,\n batchSize: this.partitionReconcilerBatchSize,\n })\n } catch (error) {\n logger.warn('Job partition reconciliation failed; it will be retried.', {error})\n return 0\n }\n }\n\n async waitForNextPartitionReconcile(workersInstance: InternalWorkersInstance, delayMs: number) {\n await new Promise<void>(resolve => {\n let resolved = false\n const finishWait = () => {\n if (resolved) return\n resolved = true\n clearTimeout(workersInstance.partitionReconcilerTimer)\n workersInstance.partitionReconcilerTimer = undefined\n workersInstance.cancelPartitionReconcilerWait = undefined\n resolve()\n }\n\n workersInstance.partitionReconcilerTimer = setTimeout(finishWait, delayMs)\n workersInstance.cancelPartitionReconcilerWait = finishWait\n })\n }\n\n async runPartitionReconcilerLoop(\n config: StartWorkersConfig,\n workersInstance: InternalWorkersInstance,\n initialReconcilePromise: Promise<number>,\n ) {\n let modifiedCount = await initialReconcilePromise\n\n while (workersInstance.running) {\n const didFillBatch = modifiedCount >= this.partitionReconcilerBatchSize\n const delayMs = didFillBatch\n ? this.partitionReconcilerBatchPauseMs\n : this.partitionReconcilerIntervalMs +\n Math.floor(Math.random() * (this.partitionReconcilerJitterMs + 1))\n\n await this.waitForNextPartitionReconcile(workersInstance, delayMs)\n if (!workersInstance.running) return\n modifiedCount = await this.reconcilePartitionBatch(config)\n }\n }\n\n createWorkersInstanceDefinition(config: StartWorkersConfig): InternalWorkersInstance {\n let signalStop!: () => void\n const stopSignal = new Promise<void>(resolve => {\n signalStop = resolve\n })\n\n const workersInstance: InternalWorkersInstance = {\n running: true,\n workersCount: config.workersCount,\n activeExecutions: new Map(),\n staleExecutions: new Map(),\n runningJobsByName: new Map(),\n jobAcquisitionHint: INITIAL_JOB_ACQUISITION_HINT,\n jobAcquisitionHintProbeCycle: 0,\n hasCompletedInitialJobAcquisitionHintProbe: false,\n pendingJobAcquisitionHintWins: 0,\n partitionOrder: createShuffledPartitions(config.nPartitions),\n partitionCursor: 0,\n jobAcquisitionHintProbePromise: Promise.resolve(),\n partitionReconcilerPromise: Promise.resolve(),\n schedulerPromise: Promise.resolve(),\n stopSignal,\n signalStop,\n get runningExecutions() {\n return this.activeExecutions.size\n },\n stop: async () => {\n if (workersInstance.stopPromise) return workersInstance.stopPromise\n\n workersInstance.stopPromise = (async () => {\n logger.info('Stopping job scheduler...')\n workersInstance.running = false\n workersInstance.signalStop()\n workersInstance.cancelJobAcquisitionHintProbeWait?.()\n workersInstance.cancelPartitionReconcilerWait?.()\n\n await Promise.all([\n workersInstance.schedulerPromise,\n workersInstance.jobAcquisitionHintProbePromise,\n workersInstance.partitionReconcilerPromise,\n ])\n\n const activeCapacity = Array.from(\n workersInstance.activeExecutions.values(),\n execution => execution.capacityPromise,\n )\n await Promise.all(activeCapacity)\n })()\n\n return workersInstance.stopPromise\n },\n }\n\n return workersInstance\n }\n\n async ensureRecords(config: StartWorkersConfig) {\n const jobs = this.getJobs(config.jobs)\n\n await Promise.all(\n jobs\n .filter(job => job.type === 'recurrent')\n .map(async job => {\n logger.debug(`Ensuring records for job \"${job.name}\"...`)\n await this.jobsRepo.ensureJobRecord(job, getRandomPartition(config.nPartitions))\n }),\n )\n }\n\n async runScheduler(config: StartWorkersConfig, workersInstance: InternalWorkersInstance) {\n logger.debug('Will ensure maxTriesReached retention and TTL index')\n void this.jobsRepo\n .ensureMaxTriesReachedRetention(config.maxTriesReachedRetentionMs)\n .catch(error => logger.error('Error ensuring maxTriesReached retention', {error}))\n\n logger.debug('Will ensure records for recurrent jobs')\n await this.ensureRecords(config)\n\n logger.info(`Starting job scheduler with concurrency ${config.workersCount}`)\n await this.runSchedulerLoop(config, workersInstance)\n }\n\n /**\n * Starts one job scheduler with the provided concurrency configuration.\n * @param userConfig - Configuration for the scheduler. Required field: jobs\n */\n startWorkers(userConfig: StartWorkersConfig): WorkersInstance {\n const maxTriesReachedRetentionMs =\n userConfig.maxTriesReachedRetentionMs === undefined\n ? DEFAULT_MAX_TRIES_REACHED_RETENTION_MS\n : userConfig.maxTriesReachedRetentionMs\n\n if (\n maxTriesReachedRetentionMs !== null &&\n (!Number.isFinite(maxTriesReachedRetentionMs) || maxTriesReachedRetentionMs < 0)\n ) {\n throw new Error('maxTriesReachedRetentionMs must be null, zero, or a positive number')\n }\n\n const nPartitions = userConfig.nPartitions ?? 1\n validatePartitionsCount(nPartitions)\n\n const config: StartWorkersConfig = {\n pollInterval: 3000,\n workersCount: 4,\n defaultLockTime: 30 * 1000,\n ...userConfig,\n nPartitions,\n maxTriesReachedRetentionMs,\n }\n\n setNameToJobs(config.jobs, config.nPartitions)\n this.jobsRepo.configureJobPartitions?.(this.getJobNames(config.jobs), config.nPartitions)\n\n const workersInstance = this.createWorkersInstanceDefinition(config)\n logger.debug('Starting job scheduler', config)\n\n workersInstance.jobAcquisitionHintProbePromise = this.runJobAcquisitionHintProbeLoop(\n config,\n workersInstance,\n )\n\n const initialReconcilePromise = this.reconcilePartitionBatch(config)\n workersInstance.partitionReconcilerPromise = this.runPartitionReconcilerLoop(\n config,\n workersInstance,\n initialReconcilePromise,\n )\n\n workersInstance.schedulerPromise = this.runScheduler(config, workersInstance).catch(error => {\n workersInstance.running = false\n workersInstance.signalStop()\n workersInstance.cancelJobAcquisitionHintProbeWait?.()\n workersInstance.cancelPartitionReconcilerWait?.()\n logger.error('Job scheduler stopped after an unexpected error.', {error})\n })\n\n return workersInstance\n }\n}\n\nfunction setNameToJobs(jobs: JobsDefinition, nPartitions: number) {\n for (const name of Object.keys(jobs)) {\n jobs[name].jobName = name\n jobs[name].nPartitions = nPartitions\n }\n}\n","import {SpanStatusCode, trace} from '@opentelemetry/api'\nimport {logger, runWithOrionAsyncContext, updateOrionAsyncContext} from '@orion-js/logger'\nimport {Blackbox} from '@orion-js/schema'\nimport {Inject, Service} from '@orion-js/services'\nimport {JobsHistoryRepo} from '../repos/JobsHistoryRepo'\nimport {JobsRepo} from '../repos/JobsRepo'\nimport {EventJobDefinition, JobDefinition, JobsDefinition} from '../types/JobsDefinition'\nimport {ExecutionContext, JobToRun} from '../types/Worker'\nimport {getNextRunDate} from './getNextRunDate'\n\n/**\n * Configuration for job execution including max tries settings.\n */\nexport interface ExecuteJobConfig {\n jobs: JobsDefinition\n maxTries?: number\n maxTriesReachedRetentionMs?: number | null\n onMaxTriesReached?: (job: JobToRun) => Promise<void>\n}\n\n@Service()\nexport class Executor {\n @Inject(() => JobsRepo)\n private readonly jobsRepo: JobsRepo\n\n @Inject(() => JobsHistoryRepo)\n private readonly jobsHistoryRepo: JobsHistoryRepo\n\n /**\n * Determines the effective lock time for a job execution.\n * Job-specific lockTime takes precedence over the default lockTime from config.\n */\n getEffectiveLockTime(job: JobDefinition, jobToRun: JobToRun): number {\n return job.lockTime ?? jobToRun.lockTime\n }\n\n getContext(\n job: JobDefinition,\n jobToRun: JobToRun,\n onStale: () => void,\n isExecutionActive: () => boolean,\n ): ExecutionContext {\n const effectiveLockTime = this.getEffectiveLockTime(job, jobToRun)\n const contextLogger = logger.addMetadata({\n jobName: jobToRun.name,\n jobId: jobToRun.jobId,\n })\n let staleTimeout: ReturnType<typeof setTimeout> | undefined\n let watchdogCleared = false\n let staleReported = false\n let pendingExtraTime: number | undefined\n let renewalRunning = false\n let renewalPromise: Promise<void> | undefined\n\n const clearCurrentStaleTimeout = () => {\n if (staleTimeout === undefined) return\n clearTimeout(staleTimeout)\n staleTimeout = undefined\n }\n\n const reportStale = () => {\n if (staleReported) return\n staleReported = true\n watchdogCleared = true\n pendingExtraTime = undefined\n clearCurrentStaleTimeout()\n onStale()\n }\n\n const armStaleTimeout = (lockedUntil: number) => {\n if (watchdogCleared || staleReported || !isExecutionActive()) return\n\n clearCurrentStaleTimeout()\n staleTimeout = setTimeout(\n () => {\n staleTimeout = undefined\n reportStale()\n },\n Math.max(0, lockedUntil - Date.now()),\n )\n staleTimeout.unref?.()\n }\n\n const runRenewals = async () => {\n try {\n while (pendingExtraTime !== undefined) {\n const extraTime = pendingExtraTime\n pendingExtraTime = undefined\n\n if (watchdogCleared || staleReported || !isExecutionActive()) {\n clearCurrentStaleTimeout()\n return\n }\n\n clearCurrentStaleTimeout()\n\n // JobsRepo calculates lockedUntil synchronously when this call starts. Keep the local\n // watchdog on that same deadline instead of adding Mongo response latency to the lock.\n const lockedUntil = Date.now() + extraTime\n let didExtend = false\n try {\n didExtend = await this.jobsRepo.extendLockTime(\n jobToRun.jobId,\n extraTime,\n jobToRun.lockId,\n )\n } catch (error) {\n reportStale()\n throw error\n }\n\n if (!didExtend) {\n reportStale()\n return\n }\n\n if (watchdogCleared || staleReported || !isExecutionActive()) {\n pendingExtraTime = undefined\n clearCurrentStaleTimeout()\n return\n }\n\n armStaleTimeout(lockedUntil)\n }\n } finally {\n // Clear the single-flight state before the promise settles so a pulse queued in the same\n // microtask checkpoint cannot attach itself to a renewal loop that has already stopped.\n renewalRunning = false\n renewalPromise = undefined\n }\n }\n\n armStaleTimeout(Date.now() + effectiveLockTime)\n\n return {\n definition: job,\n record: jobToRun,\n tries: jobToRun.tries || 0,\n clearStaleTimeout: () => {\n watchdogCleared = true\n pendingExtraTime = undefined\n clearCurrentStaleTimeout()\n },\n extendLockTime: (extraTime: number) => {\n if (watchdogCleared || staleReported || !isExecutionActive()) {\n contextLogger.warn(`Will not extend lock for stale execution \"${jobToRun.executionId}\"`)\n return Promise.resolve()\n }\n\n // One pending duration coalesces any number of pulses while Mongo is busy. Keeping the\n // longest duration prevents a shorter coalesced pulse from reducing the intended lock.\n pendingExtraTime = Math.max(pendingExtraTime ?? extraTime, extraTime)\n\n if (!renewalRunning) {\n renewalRunning = true\n renewalPromise = runRenewals()\n }\n\n return renewalPromise ?? Promise.resolve()\n },\n logger: contextLogger,\n }\n }\n\n getJobDefinition(jobToRun: JobToRun, jobs: JobsDefinition) {\n const job = jobs[jobToRun.name]\n\n if (jobToRun.type !== job.type) {\n logger.warn(\n `Job record \"${jobToRun.name}\" is \"${jobToRun.type}\" but definition is \"${job.type}\"`,\n )\n return\n }\n\n return job\n }\n\n /**\n * Determines the effective max tries for an event job.\n * Job-specific maxTries takes precedence over the global maxTries from config.\n */\n getEffectiveMaxTries(job: EventJobDefinition, globalMaxTries?: number): number | undefined {\n return job.maxTries ?? globalMaxTries\n }\n\n /**\n * Handles when a job has reached its maximum retry attempts.\n * Marks the job in the database and invokes the onMaxTriesReached callback when provided.\n */\n async handleMaxTriesReached(\n jobToRun: JobToRun,\n retentionMs?: number | null,\n onMaxTriesReached?: (job: JobToRun) => Promise<void>,\n ) {\n const jobLogger = logger.addMetadata({\n jobName: jobToRun.name,\n jobId: jobToRun.jobId,\n })\n\n jobLogger.warn(\n `Job \"${jobToRun.name}\" has exceeded max tries (${jobToRun.tries}). Marking as maxTriesReached.`,\n )\n const didMark = await this.jobsRepo.markJobAsMaxTriesReached(\n jobToRun.jobId,\n retentionMs,\n jobToRun.lockId,\n )\n\n if (!didMark) {\n jobLogger.warn(`Could not mark job \"${jobToRun.name}\" because its lock is no longer owned`)\n return false\n }\n\n if (!onMaxTriesReached) return true\n\n // Invoke the callback to notify administrators\n try {\n await onMaxTriesReached(jobToRun)\n } catch (callbackError) {\n jobLogger.error(`Error in onMaxTriesReached callback for job \"${jobToRun.name}\"`, {\n error: callbackError,\n })\n }\n\n return true\n }\n\n async onError(error: unknown, job: JobDefinition, jobToRun: JobToRun, context: ExecutionContext) {\n // Helper to schedule next run for recurrent jobs (used when dismissing)\n const scheduleRecurrent = async () => {\n if (job.type === 'recurrent') {\n return this.jobsRepo.scheduleNextRun({\n jobId: jobToRun.jobId,\n nextRunAt: getNextRunDate(job),\n resetTries: true,\n priority: job.priority,\n lockId: jobToRun.lockId,\n })\n }\n return true\n }\n\n const handleRetry = async (nextRunAt: Date) => {\n return this.jobsRepo.scheduleNextRun({\n jobId: jobToRun.jobId,\n nextRunAt,\n resetTries: false,\n priority: job.type === 'recurrent' ? job.priority : jobToRun.priority,\n lockId: jobToRun.lockId,\n })\n }\n\n if (!job.onError) {\n context.logger.error(`Error executing job \"${jobToRun.name}\"`, {error})\n\n return scheduleRecurrent()\n }\n\n context.logger.info(`Error executing job \"${jobToRun.name}\"`, {error})\n const result = await job.onError(\n error instanceof Error ? error : new Error(String(error)),\n jobToRun.params,\n context,\n )\n\n if (result.action === 'dismiss') {\n return scheduleRecurrent()\n }\n\n if (result.action === 'retry') {\n return handleRetry(getNextRunDate(result))\n }\n\n return true\n }\n\n async saveExecution(options: {\n startedAt: Date\n status: 'stale' | 'error' | 'success'\n errorMessage?: string\n result?: Blackbox\n job: JobDefinition\n jobToRun: JobToRun\n }) {\n const {startedAt, status, errorMessage, result, job, jobToRun} = options\n const endedAt = new Date()\n\n if (job.saveExecutionsFor !== 0) {\n const oneWeek = 1000 * 60 * 60 * 24 * 7\n const saveExecutionsFor = job.saveExecutionsFor || oneWeek\n await this.jobsHistoryRepo.saveExecution({\n jobId: jobToRun.jobId,\n executionId: jobToRun.executionId,\n jobName: jobToRun.name,\n type: jobToRun.type,\n priority: jobToRun.priority,\n tries: jobToRun.tries,\n uniqueIdentifier: jobToRun.uniqueIdentifier,\n startedAt,\n endedAt,\n duration: endedAt.getTime() - startedAt.getTime(),\n expiresAt: new Date(Date.now() + saveExecutionsFor),\n status,\n errorMessage,\n params: jobToRun.params,\n result,\n })\n }\n }\n\n async afterExecutionSuccess(job: JobDefinition, jobToRun: JobToRun, context: ExecutionContext) {\n if (job.type === 'recurrent') {\n context.logger.debug(`Scheduling next run for recurrent job \"${jobToRun.name}\"`)\n return this.jobsRepo.scheduleNextRun({\n jobId: jobToRun.jobId,\n nextRunAt: getNextRunDate(job),\n resetTries: true,\n priority: job.priority,\n lockId: jobToRun.lockId,\n })\n }\n if (job.type === 'event') {\n context.logger.debug(`Removing event job after success \"${jobToRun.name}\"`)\n return this.jobsRepo.deleteEventJob(jobToRun.jobId, jobToRun.lockId)\n }\n return false\n }\n\n async executeJob(config: ExecuteJobConfig, jobToRun: JobToRun, onExecutionStale: () => void) {\n const job = this.getJobDefinition(jobToRun, config.jobs)\n if (!job) return\n\n if (job.type === 'event') {\n const effectiveMaxTries = this.getEffectiveMaxTries(job, config.maxTries)\n if (typeof effectiveMaxTries === 'number' && jobToRun.tries > effectiveMaxTries) {\n await this.handleMaxTriesReached(\n jobToRun,\n config.maxTriesReachedRetentionMs,\n config.onMaxTriesReached,\n )\n return\n }\n }\n\n // If job has a custom lockTime different from the default, update the database lock\n const effectiveLockTime = this.getEffectiveLockTime(job, jobToRun)\n if (effectiveLockTime !== jobToRun.lockTime) {\n const didUpdateLock = await this.jobsRepo.updateLockTime(\n jobToRun.jobId,\n effectiveLockTime,\n jobToRun.lockId,\n )\n if (!didUpdateLock) {\n logger.warn(`Will not execute job \"${jobToRun.name}\" because its lock is no longer owned`)\n return\n }\n }\n\n const tracer = trace.getTracer('orionjs.dogs', '1.0')\n\n await tracer.startActiveSpan(`job.${jobToRun.name}.${jobToRun.executionId}`, async span => {\n try {\n const startedAt = new Date()\n let executionStatus: 'running' | 'stale' = 'running'\n let staleHandlingPromise: Promise<void> | undefined\n let context: ExecutionContext\n\n const markAsStale = () => {\n if (executionStatus === 'stale') return staleHandlingPromise\n\n executionStatus = 'stale'\n context.clearStaleTimeout()\n\n staleHandlingPromise = (async () => {\n context.logger.warn(`Job \"${jobToRun.name}\" is stale`)\n\n if (job.onStale) {\n void Promise.resolve(job.onStale(jobToRun.params, context)).catch(error => {\n context.logger.error(`Error in onStale callback for job \"${jobToRun.name}\"`, {\n error,\n })\n })\n }\n\n try {\n await this.jobsRepo.setJobRecordPriority(jobToRun.jobId, 0, jobToRun.lockId)\n } catch (error) {\n context.logger.error(`Error lowering priority for stale job \"${jobToRun.name}\"`, {\n error,\n })\n } finally {\n // Preserve the current ordering guarantee: a stale retry only becomes eligible for\n // local capacity after its priority has been lowered.\n onExecutionStale()\n }\n\n await this.saveExecution({\n startedAt,\n status: 'stale',\n result: null,\n errorMessage: null,\n job,\n jobToRun,\n })\n })().catch(error => {\n context.logger.error('Error handling stale execution', {error})\n })\n\n return staleHandlingPromise\n }\n\n context = this.getContext(\n job,\n jobToRun,\n () => void markAsStale(),\n () => executionStatus === 'running',\n )\n\n const extraContext = {\n controllerType: 'job' as const,\n jobName: jobToRun.name,\n jobId: jobToRun.jobId,\n params: jobToRun.params,\n }\n\n await runWithOrionAsyncContext(extraContext, async () => {\n try {\n // Inject async context update\n updateOrionAsyncContext({\n jobName: jobToRun.name,\n jobId: jobToRun.jobId,\n params: jobToRun.params,\n })\n const result = await job.resolve(jobToRun.params, context)\n context.clearStaleTimeout()\n\n if (executionStatus === 'stale') {\n await staleHandlingPromise\n context.logger.warn(\n `Ignoring late success from stale execution \"${jobToRun.executionId}\"`,\n )\n return\n }\n\n const stillOwnsJob = await this.afterExecutionSuccess(job, jobToRun, context)\n if (!stillOwnsJob) {\n await markAsStale()\n return\n }\n\n void this.saveExecution({\n startedAt,\n status: 'success',\n result: result || null,\n errorMessage: null,\n job,\n jobToRun,\n }).catch(error => {\n context.logger.error('Error saving successful execution history', {error})\n })\n } catch (error) {\n context.clearStaleTimeout()\n\n if (executionStatus === 'stale') {\n await staleHandlingPromise\n context.logger.warn(\n `Ignoring late error from stale execution \"${jobToRun.executionId}\"`,\n {error},\n )\n return\n }\n\n const stillOwnsJob = await this.onError(error, job, jobToRun, context)\n if (!stillOwnsJob) {\n await markAsStale()\n return\n }\n\n void this.saveExecution({\n startedAt,\n status: 'error',\n result: null,\n errorMessage: (error as Error).message,\n job,\n jobToRun,\n }).catch(saveError => {\n context.logger.error('Error saving failed execution history', {error: saveError})\n })\n }\n })\n } catch (error) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: (error as Error).message,\n })\n throw error\n } finally {\n span.end()\n }\n })\n }\n}\n","import {cleanAndValidate, SchemaInAnyOrionForm} from '@orion-js/schema'\nimport {CronExpressionParser} from 'cron-parser'\nimport parse from 'parse-duration'\nimport {ScheduleJobsResult} from '..'\nimport {scheduleJobInternal, scheduleJobsInternal} from '../schedule'\nimport {ScheduleJobOptionsWithoutName} from '../types/Events'\nimport {\n CreateEventJobOptions,\n CreateJobOptions,\n CreateRecurrentJobOptions,\n EventJobDefinition,\n JobDefinition,\n RecurrentJobDefinition,\n} from '../types/JobsDefinition'\n\nexport function createEventJob<TParamsSchema extends SchemaInAnyOrionForm>(\n options: CreateEventJobOptions<TParamsSchema>,\n): EventJobDefinition<TParamsSchema> {\n const jobDefinition: EventJobDefinition<TParamsSchema> = {\n ...options,\n type: 'event',\n schedule: null,\n scheduleJobs: null,\n }\n\n jobDefinition.schedule = async (\n scheduleOptions: ScheduleJobOptionsWithoutName<TParamsSchema>,\n ) => {\n if (!jobDefinition.jobName) {\n throw new Error('This job has not been registered in the workers')\n }\n\n const params = jobDefinition.params\n ? await cleanAndValidate(jobDefinition.params, scheduleOptions.params)\n : scheduleOptions.params\n\n return await scheduleJobInternal(\n {\n ...scheduleOptions,\n name: jobDefinition.jobName,\n params,\n },\n jobDefinition.nPartitions,\n )\n }\n\n jobDefinition.scheduleJobs = async (\n jobs: Array<ScheduleJobOptionsWithoutName<TParamsSchema>>,\n ): Promise<ScheduleJobsResult> => {\n if (!jobDefinition.jobName) {\n throw new Error('This job has not been registered in the workers')\n }\n\n // Process all job parameters if schema validation is needed\n const processedJobs = await Promise.all(\n jobs.map(async scheduleOptions => {\n const params = jobDefinition.params\n ? await cleanAndValidate(jobDefinition.params, scheduleOptions.params)\n : scheduleOptions.params\n\n return {\n ...scheduleOptions,\n name: jobDefinition.jobName,\n params,\n }\n }),\n )\n\n return await scheduleJobsInternal(processedJobs, jobDefinition.nPartitions)\n }\n\n return jobDefinition\n}\n\nexport function createRecurrentJob(options: CreateRecurrentJobOptions): RecurrentJobDefinition {\n const recurrentOptions = {\n ...options,\n } as CreateRecurrentJobOptions & {maxTries?: number}\n\n delete recurrentOptions.maxTries\n\n if ('cron' in recurrentOptions && recurrentOptions.cron && !recurrentOptions.timezone) {\n throw new Error('Cron recurrent jobs require a timezone')\n }\n\n if ('cron' in recurrentOptions && recurrentOptions.cron) {\n CronExpressionParser.parse(recurrentOptions.cron, {tz: recurrentOptions.timezone}).next()\n }\n\n const runEvery =\n 'runEvery' in recurrentOptions\n ? typeof recurrentOptions.runEvery === 'string'\n ? parse(recurrentOptions.runEvery)\n : recurrentOptions.runEvery\n : undefined\n\n const jobDefinition: RecurrentJobDefinition = {\n ...recurrentOptions,\n priority: recurrentOptions.priority ?? 100,\n type: 'recurrent',\n runEvery,\n }\n\n return jobDefinition\n}\n\n/**\n * @deprecated Use `createEventJob` or `createRecurrentJob` instead.\n */\nexport const defineJob = (\n options: CreateJobOptions & {type: 'event' | 'recurrent'},\n): JobDefinition => {\n return options.type === 'event'\n ? createEventJob(options as any)\n : createRecurrentJob(options as any)\n}\n","import {getInstance, Service} from '@orion-js/services'\nimport {createEventJob, defineJob} from '../defineJob'\nimport type {CreateEventJobOptions, JobDefinition, RecurrentJobDefinition} from '../types'\n\n// Define metadata storage using WeakMaps\nconst serviceMetadata = new WeakMap<any, {_serviceType: string}>()\nconst jobsMetadata = new Map<any, Record<string, any>>()\nconst jobEntriesByClass = new Map<Function, Record<string, (instance: any) => any>>()\nlet pendingJobEntries: Record<string, (instance: any) => any> = {}\n\nexport function Jobs() {\n return (target: any, context: ClassDecoratorContext<any>) => {\n Service()(target, context)\n serviceMetadata.set(target, {_serviceType: 'jobs'})\n\n if (Object.keys(pendingJobEntries).length > 0) {\n jobEntriesByClass.set(target, pendingJobEntries)\n pendingJobEntries = {}\n }\n }\n}\n\nexport function RecurrentJob(): (\n method: any,\n context: ClassFieldDecoratorContext | ClassMethodDecoratorContext,\n) => any\nexport function RecurrentJob(\n options: Omit<RecurrentJobDefinition, 'resolve' | 'type'>,\n): (method: any, context: ClassMethodDecoratorContext) => any\nexport function RecurrentJob(options = {}) {\n return (method: any, context: ClassFieldDecoratorContext | ClassMethodDecoratorContext) => {\n const propertyKey = String(context.name)\n\n if (context.kind === 'method') {\n pendingJobEntries[propertyKey] = (instance: any) =>\n defineJob({\n ...options,\n type: 'recurrent',\n resolve: instance[propertyKey].bind(instance),\n })\n }\n\n if (context.kind === 'field') {\n pendingJobEntries[propertyKey] = (instance: any) => instance[propertyKey]\n }\n\n return method\n }\n}\n\nexport function EventJob(): (\n method: any,\n context: ClassFieldDecoratorContext | ClassMethodDecoratorContext,\n) => any\nexport function EventJob(\n options: Omit<CreateEventJobOptions<any>, 'resolve'>,\n): (method: any, context: ClassMethodDecoratorContext) => any\nexport function EventJob(options = {}) {\n return (method: any, context: ClassFieldDecoratorContext | ClassMethodDecoratorContext) => {\n const propertyKey = String(context.name)\n\n if (context.kind === 'method') {\n pendingJobEntries[propertyKey] = (instance: any) =>\n createEventJob({\n ...options,\n resolve: instance[propertyKey].bind(instance),\n })\n }\n\n if (context.kind === 'field') {\n pendingJobEntries[propertyKey] = (instance: any) => instance[propertyKey]\n }\n\n return method\n }\n}\n\nfunction initializeJobsIfNeeded(instance: any) {\n if (jobsMetadata.has(instance)) return\n const entries = jobEntriesByClass.get(instance.constructor) || {}\n const jobs: Record<string, any> = {}\n for (const [key, setup] of Object.entries(entries)) {\n jobs[key] = setup(instance)\n }\n jobsMetadata.set(instance, jobs)\n}\n\nexport function getServiceJobs(target: any): {\n [key: string]: JobDefinition\n} {\n const instance = getInstance(target)\n\n if (!serviceMetadata.has(instance.constructor)) {\n throw new Error('You must pass a class decorated with @Jobs to getServiceJobs')\n }\n\n const instanceMetadata = serviceMetadata.get(instance.constructor)\n if (instanceMetadata._serviceType !== 'jobs') {\n throw new Error('You must pass a class decorated with @Jobs to getServiceJobs')\n }\n\n initializeJobsIfNeeded(instance)\n\n const jobsMap = jobsMetadata.get(instance) || {}\n\n return jobsMap\n}\n"],"mappings":"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","names":["import_services","import_mongodb","import_schema","import_schema","_init","import_services","import_logger","_init","import_helpers","import_logger","import_services","import_logger","import_services","_jobsRepo_dec","_init","_jobsRepo_dec","_init","_a","_b","import_schema","import_cron_parser","parse","import_services"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/repos/JobsHistoryRepo.ts","../../../node_modules/.bun/rambdax@11.3.1/node_modules/rambdax/src/_internals/isInteger.js","../../../node_modules/.bun/rambdax@11.3.1/node_modules/rambdax/src/_internals/createPath.js","../../../node_modules/.bun/rambdax@11.3.1/node_modules/rambdax/src/_internals/compare.js","../../../node_modules/.bun/rambdax@11.3.1/node_modules/rambdax/src/_internals/includes.js","../../../node_modules/.bun/rambdax@11.3.1/node_modules/rambdax/src/omit.js","../src/types/HistoryRecord.ts","../src/repos/JobsRepo.ts","../src/services/partitions.ts","../src/types/JobRecord.ts","../src/types/StartConfig.ts","../src/schedule.ts","../src/services/EventsService.ts","../src/services/getNextRunDate.ts","../src/services/WorkerService.ts","../src/services/Executor.ts","../src/defineJob/index.ts","../src/service/index.ts"],"sourcesContent":["import {SchemaInAnyOrionForm} from '@orion-js/schema'\nimport {getInstance} from '@orion-js/services'\nimport {JobsHistoryRepo} from './repos/JobsHistoryRepo'\nimport {JobsRepo} from './repos/JobsRepo'\nimport {scheduleJobInternal, scheduleJobsInternal} from './schedule'\nimport {WorkerService} from './services/WorkerService'\nimport {ScheduleJobOptions, ScheduleJobsOptions, ScheduleJobsResult} from './types/Events'\nimport {StartWorkersConfig} from './types/StartConfig'\n\nexport * from './defineJob'\nexport * from './service'\nexport * from './types'\n\nconst workerService = getInstance(WorkerService)\nconst jobsHistoryRepo = getInstance(JobsHistoryRepo)\nconst jobsRepo = getInstance(JobsRepo)\n\nconst startWorkers = (config: StartWorkersConfig) => {\n return workerService.startWorkers(config)\n}\n\n/**\n * @deprecated Use the event job definition.schedule method instead.\n */\nconst scheduleJob = <TParamsSchema extends SchemaInAnyOrionForm = any>(\n options: ScheduleJobOptions<TParamsSchema>,\n) => {\n return scheduleJobInternal(options)\n}\n\n/**\n * Schedule multiple jobs at once for better performance.\n * @deprecated Use the event job definition.scheduleJobs method instead.\n */\nconst scheduleJobs = <TParamsSchema extends SchemaInAnyOrionForm = any>(\n jobs: ScheduleJobsOptions<TParamsSchema>,\n): Promise<ScheduleJobsResult> => {\n return scheduleJobsInternal(jobs)\n}\n\nexport {startWorkers, scheduleJob, scheduleJobs, jobsHistoryRepo, jobsRepo}\n","import {Collection, MongoCollection, Repository, MongoDB} from '@orion-js/mongodb'\nimport {omit} from 'rambdax'\nimport {HistoryRecord, HistoryRecordSchema} from '../types/HistoryRecord'\n\n@Repository()\nexport class JobsHistoryRepo {\n @MongoCollection({\n name: 'orionjs.jobs_dogs_history',\n idGeneration: 'uuid',\n schema: HistoryRecordSchema,\n indexes: [\n {\n keys: {\n jobName: 1,\n startedAt: 1,\n },\n },\n {\n keys: {\n executionId: 1,\n },\n },\n {\n keys: {\n expiresAt: 1,\n },\n options: {\n expireAfterSeconds: 0,\n },\n },\n ],\n })\n history: Collection<HistoryRecord>\n\n async saveExecution(record: MongoDB.WithoutId<HistoryRecord>) {\n await this.history.upsert(\n {executionId: record.executionId},\n {\n $setOnInsert: {\n status: record.status,\n },\n $set: {\n ...omit(['status'], record),\n },\n },\n )\n }\n\n async getExecutions(jobName: string, limit?: number, skip?: number): Promise<HistoryRecord[]> {\n const cursor = this.history.find({jobName}).sort({startedAt: -1})\n\n if (skip) {\n cursor.skip(skip)\n }\n\n if (limit) {\n cursor.limit(limit)\n }\n\n return await cursor.toArray()\n }\n}\n","function _isInteger(n){\n return n << 0 === n\n}\n\nexport const isInteger = Number.isInteger || _isInteger\n\n/**\n * Check if `index` is integer even if it is a string.\n */\nexport const isIndexInteger = index => Number.isInteger(Number(index))\n","import { isInteger } from './isInteger.js'\n\nexport function createPath(path, delimiter = '.'){\n return typeof path === 'string' ?\n path.split(delimiter).map(x => isInteger(x) ? Number(x) : x) :\n path\n}\n","export function compare(a, b){\n return String(a) === String(b)\n}\n","import { compare } from './compare.js'\n\nexport function includes(a, list){\n let index = -1\n const { length } = list\n\n while (++index < length)\n if (compare(list[ index ], a))\n return true\n\n return false\n}\n","import { createPath } from './_internals/createPath.js'\nimport { includes } from './_internals/includes.js'\n\nexport function omit(propsToOmit, obj){\n if (arguments.length === 1) return _obj => omit(propsToOmit, _obj)\n\n if (obj === null || obj === undefined)\n return undefined\n\n const propsToOmitValue = createPath(propsToOmit, ',')\n const willReturn = {}\n\n for (const key in obj)\n if (!includes(key, propsToOmitValue))\n willReturn[ key ] = obj[ key ]\n\n return willReturn\n}\n","import {InferSchemaType, schemaWithName} from '@orion-js/schema'\n\nexport const HistoryRecordSchema = schemaWithName('HistoryRecord', {\n _id: {type: 'string'},\n jobId: {type: 'string'},\n executionId: {type: 'string'},\n jobName: {type: 'string'},\n type: {type: 'string'},\n priority: {type: 'number'},\n tries: {type: 'number'},\n uniqueIdentifier: {type: 'string', optional: true},\n startedAt: {type: 'date'},\n endedAt: {type: 'date'},\n duration: {type: 'number'},\n expiresAt: {type: 'date', optional: true},\n status: {type: 'string', enum: ['success', 'error', 'stale']},\n errorMessage: {type: 'string', optional: true},\n params: {type: 'blackbox', optional: true},\n result: {type: 'any', optional: true},\n})\n\nexport type HistoryRecord = InferSchemaType<typeof HistoryRecordSchema>\n","import {generateId} from '@orion-js/helpers'\nimport {logger} from '@orion-js/logger'\nimport {Collection, MongoCollection, MongoDB, Repository} from '@orion-js/mongodb'\nimport {clean, validate} from '@orion-js/schema'\nimport {getRandomPartition} from '../services/partitions'\nimport {ScheduleJobRecordOptions, ScheduleJobsResult} from '../types/Events'\nimport {JobRecord, JobRecordSchema} from '../types/JobRecord'\nimport {JobDefinitionWithName, RecurrentJobDefinition} from '../types/JobsDefinition'\nimport {DEFAULT_MAX_TRIES_REACHED_RETENTION_MS} from '../types/StartConfig'\nimport {JobToRun} from '../types/Worker'\n\nexport type JobAcquisitionHint = 'byJobName' | 'globalPriority'\n\nexport const JOB_ACQUISITION_HINTS = {\n byJobName: {\n partition: 1,\n jobName: 1,\n priority: -1,\n nextRunAt: 1,\n },\n globalPriority: {\n partition: 1,\n priority: -1,\n nextRunAt: 1,\n },\n} as const satisfies Record<JobAcquisitionHint, MongoDB.IndexSpecification>\n\nexport const INITIAL_JOB_ACQUISITION_HINT = 'byJobName' as const satisfies JobAcquisitionHint\nexport const CANDIDATE_JOB_ACQUISITION_HINT = 'globalPriority' as const satisfies JobAcquisitionHint\n\nconst SORTED_UPDATE_ONE_MIN_WIRE_VERSION = 25\nconst LOCK_ID_INDEX_NAME = 'jobs_dogs_records_lock_id'\nconst PARTITION_JOB_NAME_INDEX_NAME = 'jobs_dogs_records_partition_job_name_priority_next_run'\nconst PARTITION_PRIORITY_INDEX_NAME = 'jobs_dogs_records_partition_priority_next_run'\n\nconst JOB_ACQUISITION_SORT: MongoDB.Sort = {\n priority: -1,\n nextRunAt: 1,\n}\n\nfunction getJobAcquisitionSelector(\n jobNames: string[],\n now: Date,\n partition: number,\n): MongoDB.Filter<JobRecord> {\n return {\n partition,\n jobName: {$in: jobNames},\n nextRunAt: {$lte: now},\n $and: [\n {$or: [{lockedUntil: {$exists: false}}, {lockedUntil: {$lte: now}}]},\n // Exclude event jobs that have reached max tries. Recurrent jobs keep running even\n // if old records still have this status from previous versions.\n {$or: [{type: {$ne: 'event'}}, {status: {$ne: 'maxTriesReached'}}]},\n ],\n }\n}\n\n@Repository()\nexport class JobsRepo {\n @MongoCollection({\n idGeneration: 'uuid',\n name: 'orionjs.jobs_dogs_records',\n schema: JobRecordSchema,\n indexes: [\n {\n keys: JOB_ACQUISITION_HINTS.byJobName,\n options: {name: PARTITION_JOB_NAME_INDEX_NAME},\n },\n {\n keys: JOB_ACQUISITION_HINTS.globalPriority,\n options: {name: PARTITION_PRIORITY_INDEX_NAME},\n },\n {\n keys: {\n jobName: 1,\n },\n options: {\n unique: true,\n partialFilterExpression: {type: 'recurrent'},\n },\n },\n {\n keys: {\n uniqueIdentifier: 1,\n },\n options: {\n unique: true,\n sparse: true,\n },\n },\n {\n keys: {\n lockId: 1,\n },\n options: {\n name: LOCK_ID_INDEX_NAME,\n sparse: true,\n },\n },\n {\n keys: {\n expiresAt: 1,\n },\n name: 'jobs_dogs_records_expires_at_ttl',\n expireAfterSeconds: 0,\n },\n ],\n })\n jobs: Collection<JobRecord>\n\n private sortedUpdateOneSupportPromise?: Promise<boolean>\n private partitionsByJobName = new Map<string, number>()\n\n configureJobPartitions(jobNames: string[], nPartitions: number) {\n for (const jobName of jobNames) {\n this.partitionsByJobName.set(jobName, nPartitions)\n }\n }\n\n getJobPartitionsCount(jobName: string) {\n return this.partitionsByJobName.get(jobName)\n }\n\n async supportsSortedUpdateOne(): Promise<boolean> {\n if (!this.sortedUpdateOneSupportPromise) {\n this.sortedUpdateOneSupportPromise = this.detectSortedUpdateOneSupport()\n }\n\n return this.sortedUpdateOneSupportPromise\n }\n\n private async detectSortedUpdateOneSupport(): Promise<boolean> {\n const rawCollection = await this.jobs.getRawCollection()\n // Both acquisition implementations use explicit hints, so the first claim must wait until the\n // declared indexes are ready even when the server needs the legacy fallback.\n await this.jobs.createIndexesPromise\n const hello = await rawCollection.db.admin().command({hello: 1})\n const supportsSortedUpdateOne =\n typeof hello.maxWireVersion === 'number' &&\n hello.maxWireVersion >= SORTED_UPDATE_ONE_MIN_WIRE_VERSION\n\n if (!supportsSortedUpdateOne) {\n logger.info('MongoDB does not support sorted updateOne; using findOneAndUpdate for jobs.')\n return false\n }\n\n const hasLockIdIndex = await rawCollection.indexExists(LOCK_ID_INDEX_NAME)\n if (!hasLockIdIndex) {\n logger.warn(\n `MongoDB supports sorted updateOne but index \"${LOCK_ID_INDEX_NAME}\" is unavailable; using findOneAndUpdate for jobs.`,\n )\n return false\n }\n\n logger.info('MongoDB supports sorted updateOne; using it for job acquisition.')\n return true\n }\n\n async getJobAndLock(\n jobNames: string[],\n lockTime: number,\n hint: JobAcquisitionHint = INITIAL_JOB_ACQUISITION_HINT,\n partition = 0,\n ): Promise<JobToRun> {\n if (await this.supportsSortedUpdateOne()) {\n return this.getJobAndLockWithSortedUpdateOne(jobNames, lockTime, hint, partition)\n }\n\n return this.getJobAndLockWithFindOneAndUpdate(jobNames, lockTime, hint, partition)\n }\n\n private async getJobAndLockWithFindOneAndUpdate(\n jobNames: string[],\n lockTime: number,\n hint: JobAcquisitionHint,\n partition: number,\n ): Promise<JobToRun> {\n const executionId = generateId()\n const now = new Date()\n const lockedUntil = new Date(now.getTime() + lockTime)\n\n const job = await this.jobs.findOneAndUpdate(\n getJobAcquisitionSelector(jobNames, now, partition),\n {\n $set: {lockId: executionId, lockedUntil, lastRunAt: now},\n $inc: {tries: 1},\n },\n {\n mongoOptions: {\n hint: JOB_ACQUISITION_HINTS[hint],\n sort: JOB_ACQUISITION_SORT,\n returnDocument: 'before',\n },\n },\n )\n\n if (!job) return\n\n const tries = (job.tries || 0) + 1\n const wasStale = Boolean(job.lockedUntil)\n\n return this.toJobToRun(job, executionId, lockTime, tries, wasStale)\n }\n\n private async getJobAndLockWithSortedUpdateOne(\n jobNames: string[],\n lockTime: number,\n hint: JobAcquisitionHint,\n partition: number,\n ): Promise<JobToRun> {\n const executionId = generateId()\n const now = new Date()\n const lockedUntil = new Date(now.getTime() + lockTime)\n const rawCollection = await this.jobs.getRawCollection()\n\n const result = await rawCollection.updateOne(\n getJobAcquisitionSelector(jobNames, now, partition),\n [\n {\n $set: {\n lockId: {$literal: executionId},\n lockedUntil: {$literal: lockedUntil},\n lastRunAt: {$literal: now},\n tries: {$add: [{$ifNull: ['$tries', 0]}, 1]},\n claimWasStale: {$eq: [{$type: '$lockedUntil'}, 'date']},\n },\n },\n ],\n {\n hint: JOB_ACQUISITION_HINTS[hint],\n sort: JOB_ACQUISITION_SORT,\n },\n )\n\n if (result.matchedCount === 0) return\n\n const job = await rawCollection.findOne({lockId: executionId})\n if (!job) return\n\n return this.toJobToRun(job, executionId, lockTime, job.tries || 0, Boolean(job.claimWasStale))\n }\n\n private toJobToRun(\n job: JobRecord,\n executionId: string,\n lockTime: number,\n tries: number,\n wasStale: boolean,\n ): JobToRun {\n if (wasStale) {\n logger.info(`Running job \"${job.jobName}\" that was staled`)\n }\n\n return {\n jobId: job._id,\n executionId,\n lockId: executionId,\n name: job.jobName,\n params: job.params,\n type: job.type,\n tries,\n lockTime,\n priority: job.priority,\n uniqueIdentifier: job.uniqueIdentifier,\n wasStale,\n }\n }\n\n async getJobAcquisitionExecutionTime(\n jobNames: string[],\n hint: JobAcquisitionHint,\n partition = 0,\n ): Promise<number> {\n const explain = await this.jobs\n .find(getJobAcquisitionSelector(jobNames, new Date(), partition), {\n hint: JOB_ACQUISITION_HINTS[hint],\n maxTimeMS: 1000,\n readPreference: 'primary',\n })\n .sort(JOB_ACQUISITION_SORT)\n .limit(1)\n .explain('executionStats')\n\n const executionTimeMillis = explain.executionStats?.executionTimeMillis\n if (typeof executionTimeMillis !== 'number' || !Number.isFinite(executionTimeMillis)) {\n throw new Error(`Explain for acquisition hint \"${hint}\" returned no execution time`)\n }\n\n return executionTimeMillis\n }\n\n async setJobRecordPriority(jobId: string, priority: number, lockId?: string) {\n const result = await this.jobs.updateOne(lockId ? {_id: jobId, lockId} : jobId, {\n $set: {priority},\n })\n return result.matchedCount > 0\n }\n\n async scheduleNextRun(options: {\n jobId: string\n nextRunAt: Date\n resetTries: boolean\n priority: number\n lockId?: string\n }) {\n const updator: MongoDB.UpdateFilter<JobRecord> = {\n $set: {\n nextRunAt: options.nextRunAt,\n priority: options.priority,\n ...(options.resetTries ? {tries: 0} : {}),\n },\n $unset: {lockId: '', lockedUntil: '', claimWasStale: ''},\n }\n\n const result = await this.jobs.updateOne(\n options.lockId ? {_id: options.jobId, lockId: options.lockId} : options.jobId,\n updator,\n )\n return result.matchedCount > 0\n }\n\n async rescheduleAfterExecutionGuardAcquisitionFailure(\n jobId: string,\n lockId: string,\n nextRunAt: Date,\n ) {\n const result = await this.jobs.updateOne(\n {_id: jobId, lockId, tries: {$gte: 1}},\n {\n $set: {nextRunAt},\n $inc: {tries: -1},\n $unset: {lockId: '', lockedUntil: '', claimWasStale: ''},\n },\n )\n return result.matchedCount > 0\n }\n\n async deleteEventJob(jobId: string, lockId?: string) {\n const result = await this.jobs.deleteOne({\n _id: jobId,\n type: 'event',\n ...(lockId ? {lockId} : {}),\n })\n return result.deletedCount > 0\n }\n\n /**\n * Marks an event job as having reached its maximum tries limit.\n * The job won't be picked up for execution and MongoDB will delete it after\n * the configured retention period.\n */\n async markJobAsMaxTriesReached(\n jobId: string,\n retentionMs: number | null = DEFAULT_MAX_TRIES_REACHED_RETENTION_MS,\n lockId?: string,\n ) {\n const maxTriesReachedAt = new Date()\n const result = await this.jobs.updateOne(\n {_id: jobId, type: 'event', ...(lockId ? {lockId} : {})},\n {\n $set: {\n status: 'maxTriesReached',\n maxTriesReachedAt,\n ...(retentionMs === null\n ? {}\n : {expiresAt: new Date(maxTriesReachedAt.getTime() + retentionMs)}),\n },\n $unset: {\n lockId: '',\n lockedUntil: '',\n claimWasStale: '',\n ...(retentionMs === null ? {expiresAt: ''} : {}),\n },\n },\n )\n return result.matchedCount > 0\n }\n\n /**\n * Applies the current retention configuration to existing maxTriesReached\n * event jobs. The collection definition ensures the TTL index. Legacy records\n * use lastRunAt as their retention anchor when available.\n */\n async ensureMaxTriesReachedRetention(retentionMs: number | null) {\n const selector = {\n type: 'event' as const,\n status: 'maxTriesReached' as const,\n }\n\n if (retentionMs === null) {\n await this.jobs.updateMany(selector, {$unset: {expiresAt: ''}})\n return\n }\n\n const now = new Date()\n const retentionAnchor = {\n $ifNull: ['$maxTriesReachedAt', {$ifNull: ['$lastRunAt', now]}],\n }\n\n await this.jobs.rawCollection.updateMany(selector, [\n {\n $set: {\n maxTriesReachedAt: retentionAnchor,\n expiresAt: {$add: [retentionAnchor, retentionMs]},\n },\n },\n ])\n }\n\n async extendLockTime(jobId: string, extraTime: number, lockId?: string) {\n return this.updateLockTime(jobId, extraTime, lockId)\n }\n\n /**\n * Updates the lock time for a job to the specified duration from now.\n * Can be used to both extend or shorten the lock time.\n */\n async updateLockTime(jobId: string, lockDuration: number, lockId?: string) {\n const lockedUntil = new Date(Date.now() + lockDuration)\n const result = await this.jobs.updateOne(\n {_id: jobId, ...(lockId ? {lockId} : {})},\n {\n $set: {lockedUntil},\n },\n )\n return result.matchedCount > 0\n }\n\n async unlockAllJobs(): Promise<number> {\n const result = await this.jobs.updateMany(\n {\n lockedUntil: {$exists: true},\n },\n {\n $unset: {lockId: '', lockedUntil: '', claimWasStale: ''},\n },\n )\n\n return result.modifiedCount\n }\n\n async ensureJobRecord(job: JobDefinitionWithName, partition = 0) {\n const result = await this.jobs.upsert(\n {\n jobName: job.name,\n },\n {\n $set: {\n type: job.type,\n priority: (job as RecurrentJobDefinition).priority,\n },\n $unset: {\n status: '',\n },\n $setOnInsert: {\n nextRunAt: new Date(),\n partition,\n },\n },\n )\n\n if (result.upsertedId) {\n logger.debug(`Created job record for \"${job.name}\"`)\n } else {\n logger.debug(`Record for job \"${job.name}\" already exists`)\n }\n }\n\n async scheduleJob(options: ScheduleJobRecordOptions) {\n try {\n await this.jobs.insertOne({\n jobName: options.name,\n uniqueIdentifier: options.uniqueIdentifier,\n params: options.params,\n nextRunAt: options.nextRunAt,\n priority: options.priority,\n type: 'event',\n ...(options.partition === undefined ? {} : {partition: options.partition}),\n })\n } catch (error) {\n if (\n error.isValidationError &&\n Object.values(error.validationErrors).includes('notUnique') &&\n options.uniqueIdentifier\n ) {\n logger.info(\n `Job \"${options.name}\" with identifier \"${options.uniqueIdentifier}\" already exists`,\n )\n } else {\n throw error\n }\n }\n }\n\n async scheduleJobs(jobs: ScheduleJobRecordOptions[]): Promise<ScheduleJobsResult> {\n if (jobs.length === 0) {\n return {scheduledCount: 0, skippedCount: 0, errors: []}\n }\n\n const errors: Array<{index: number; error: Error; job: ScheduleJobRecordOptions}> = []\n const preparedJobs: Array<{\n index: number\n job: ScheduleJobRecordOptions\n record: JobRecord\n }> = []\n\n for (let i = 0; i < jobs.length; i++) {\n const job = jobs[i]\n try {\n const record = (await clean(JobRecordSchema, {\n _id: this.jobs.generateId(),\n jobName: job.name,\n uniqueIdentifier: job.uniqueIdentifier,\n params: job.params,\n nextRunAt: job.nextRunAt,\n priority: job.priority,\n type: 'event',\n ...(job.partition === undefined ? {} : {partition: job.partition}),\n })) as JobRecord\n await validate(JobRecordSchema, record)\n preparedJobs.push({index: i, job, record})\n } catch (error) {\n errors.push({\n index: i,\n error: error instanceof Error ? error : new Error(String(error)),\n job,\n })\n }\n }\n\n if (preparedJobs.length === 0) {\n return {scheduledCount: 0, skippedCount: 0, errors}\n }\n\n const rawCollection = await this.jobs.getRawCollection()\n await this.jobs.createIndexesPromise\n const operations: MongoDB.AnyBulkWriteOperation<JobRecord>[] = preparedJobs.map(({record}) =>\n record.uniqueIdentifier === undefined\n ? {insertOne: {document: record}}\n : {\n updateOne: {\n filter: {uniqueIdentifier: record.uniqueIdentifier},\n update: {$setOnInsert: record},\n upsert: true,\n },\n },\n )\n\n let scheduledCount = 0\n let skippedCount = 0\n\n try {\n const result = await rawCollection.bulkWrite(operations, {ordered: false})\n scheduledCount = result.insertedCount + result.upsertedCount\n skippedCount = result.matchedCount\n } catch (error) {\n const writeErrors =\n error instanceof MongoDB.MongoBulkWriteError\n ? Array.isArray(error.writeErrors)\n ? error.writeErrors\n : [error.writeErrors]\n : []\n\n if (!(error instanceof MongoDB.MongoBulkWriteError) || writeErrors.length === 0) {\n for (const preparedJob of preparedJobs) {\n errors.push({\n index: preparedJob.index,\n error: error instanceof Error ? error : new Error(String(error)),\n job: preparedJob.job,\n })\n }\n } else {\n scheduledCount = error.result.insertedCount + error.result.upsertedCount\n skippedCount = error.result.matchedCount\n\n for (const writeError of writeErrors) {\n const preparedJob = preparedJobs[writeError.index]\n if (!preparedJob) continue\n\n if (writeError.code === 11000 && preparedJob.record.uniqueIdentifier !== undefined) {\n skippedCount++\n continue\n }\n\n errors.push({\n index: preparedJob.index,\n error: new Error(writeError.errmsg),\n job: preparedJob.job,\n })\n }\n }\n }\n\n logger.debug(\n `Scheduled ${scheduledCount} jobs successfully, skipped ${skippedCount}, errors: ${errors.length}`,\n )\n\n return {\n scheduledCount,\n skippedCount,\n errors,\n }\n }\n\n async reconcilePartitions(options: {\n jobNames: string[]\n nPartitions: number\n batchSize: number\n }): Promise<number> {\n if (options.jobNames.length === 0) return 0\n\n const rawCollection = await this.jobs.getRawCollection()\n await this.jobs.createIndexesPromise\n const now = new Date()\n const invalidPartition: MongoDB.Filter<JobRecord> = {\n $or: [\n {partition: {$exists: false}},\n {partition: {$lt: 0}},\n {partition: {$gte: options.nPartitions}},\n ],\n }\n const availableLock: MongoDB.Filter<JobRecord> = {\n $or: [{lockedUntil: {$exists: false}}, {lockedUntil: {$lte: now}}],\n }\n const runnableJob: MongoDB.Filter<JobRecord> = {\n $or: [{type: {$ne: 'event'}}, {status: {$ne: 'maxTriesReached'}}],\n }\n\n const jobs = await rawCollection\n .find({\n jobName: {$in: options.jobNames},\n $and: [invalidPartition, availableLock, runnableJob],\n })\n .project({_id: 1})\n .limit(options.batchSize)\n .toArray()\n\n if (jobs.length === 0) return 0\n\n const result = await rawCollection.bulkWrite(\n jobs.map(job => ({\n updateOne: {\n filter: {\n _id: job._id,\n $and: [invalidPartition, availableLock, runnableJob],\n },\n update: {$set: {partition: getRandomPartition(options.nPartitions)}},\n },\n })),\n {ordered: false},\n )\n\n return result.modifiedCount\n }\n}\n","export function validatePartitionsCount(nPartitions: number) {\n if (!Number.isInteger(nPartitions) || nPartitions <= 0) {\n throw new Error('nPartitions must be a positive integer')\n }\n}\n\nexport function getRandomPartition(nPartitions: number) {\n return Math.floor(Math.random() * nPartitions)\n}\n\nexport function createShuffledPartitions(nPartitions: number) {\n const partitions = Array.from({length: nPartitions}, (_, partition) => partition)\n\n for (let index = partitions.length - 1; index > 0; index--) {\n const swapIndex = Math.floor(Math.random() * (index + 1))\n ;[partitions[index], partitions[swapIndex]] = [partitions[swapIndex], partitions[index]]\n }\n\n return partitions\n}\n","import {createEnum, InferSchemaType, schemaWithName} from '@orion-js/schema'\n\n/**\n * Enum representing the status of a job record.\n * - 'pending': Job is active and can be executed (default for existing records)\n * - 'maxTriesReached': Event job has exhausted all retry attempts and won't be executed\n */\nexport const JobStatusEnum = createEnum('JobStatus', ['pending', 'maxTriesReached'])\n\nexport const JobRecordSchema = schemaWithName('JobRecord', {\n _id: {type: 'string'},\n jobName: {type: 'string'},\n type: {type: createEnum('JobType', ['recurrent', 'event'])},\n priority: {type: 'number'},\n uniqueIdentifier: {type: 'string', optional: true},\n nextRunAt: {type: 'date'},\n /**\n * Acquisition partition. Optional so records created by previous versions can be reconciled.\n */\n partition: {type: 'number', optional: true},\n lastRunAt: {type: 'date', optional: true},\n lockedUntil: {type: 'date', optional: true},\n /**\n * Identifies the execution that currently owns the lock. Mutations from an execution must match\n * this value so a stale execution cannot modify a newer claim.\n */\n lockId: {type: 'string', optional: true},\n /**\n * Internal acquisition metadata used when MongoDB supports sorted updateOne. It preserves the\n * pre-update stale state because updateOne intentionally does not return the previous document.\n */\n claimWasStale: {type: 'boolean', optional: true},\n tries: {type: 'number', optional: true},\n params: {type: 'blackbox', optional: true},\n /**\n * Status of the job. Optional for backwards compatibility with existing records.\n * Records without this field are treated as 'pending'.\n */\n status: {type: JobStatusEnum, optional: true},\n /**\n * Date when the job reached its maximum tries. Used as the stable anchor when\n * maxTriesReachedRetentionMs changes between worker restarts.\n */\n maxTriesReachedAt: {type: 'date', optional: true},\n /**\n * Date when MongoDB should remove a terminal event job through the TTL index.\n */\n expiresAt: {type: 'date', optional: true},\n})\n\nexport type JobRecord = InferSchemaType<typeof JobRecordSchema>\n","import {JobsDefinition} from './JobsDefinition'\nimport {JobToRun} from './Worker'\n\nexport type LogLevels = 'debug' | 'info' | 'warn' | 'error' | 'none'\n\nexport const DEFAULT_MAX_TRIES_REACHED_RETENTION_MS = 1000 * 60 * 60 * 24 * 7\n\n/**\n * A lease held for the duration of one job resolver execution.\n */\nexport interface WorkerExecutionGuardLease {\n release(): Promise<void>\n}\n\n/**\n * Acquires infrastructure protection for a claimed job before its resolver starts.\n */\nexport interface WorkerExecutionGuard {\n acquire(job: JobToRun): Promise<WorkerExecutionGuardLease>\n}\n\nexport interface StartWorkersConfig {\n /**\n * Object map of the jobs that this scheduler will execute.\n */\n jobs: JobsDefinition\n /**\n * Maximum number of tries for an event job before it is marked as 'maxTriesReached'.\n * This is a global default that can be overridden per event job definition.\n */\n maxTries?: number\n /**\n * Time in milliseconds to keep event jobs after they reach their maximum tries.\n * Defaults to one week. Set to null to keep them indefinitely.\n */\n maxTriesReachedRetentionMs?: number | null\n /**\n * Callback invoked when an event job reaches its maximum tries limit.\n * Use this to notify administrators (e.g., send an email alert).\n * The job will remain in the database with status 'maxTriesReached' until its\n * configured retention period expires.\n */\n onMaxTriesReached?: (job: JobToRun) => Promise<void>\n /**\n * Optional infrastructure guard acquired after a job is claimed and before its resolver starts.\n * The returned lease is held until the resolver's Promise settles, including late stale\n * executions. Acquisition failures safely requeue the job without consuming a business try.\n */\n executionGuard?: WorkerExecutionGuard\n /**\n * Time in milliseconds to wait between each look without results for a job\n * to run at the database. Default is 3000.\n */\n pollInterval?: number\n /**\n * @deprecated The centralized scheduler no longer waits after successful job acquisition or\n * execution. This option is accepted for backwards compatibility and ignored.\n */\n cooldownPeriod?: number\n /**\n * Maximum number of concurrent job executions for this scheduler. Default is 4.\n */\n workersCount?: number\n /**\n * Number of database partitions used to spread job acquisition contention.\n * Each claim queries exactly one partition. Default is 1.\n */\n nPartitions?: number\n /**\n * Default time in milliseconds to lock a job for execution. Default is 30000 (30 seconds).\n * If a job is locked for longer than this time, it will be considered as failed.\n * This is to prevent a job from being executed multiple times at the same time.\n * You can extend this time inside a job by calling extendLockTime from context.\n * Individual jobs can override this value by setting their own lockTime.\n */\n defaultLockTime?: number\n}\n","import {SchemaInAnyOrionForm} from '@orion-js/schema'\nimport {getInstance} from '@orion-js/services'\nimport {EventsService} from './services/EventsService'\nimport {ScheduleJobOptions, ScheduleJobsOptions, ScheduleJobsResult} from './types/Events'\n\nconst eventsService = getInstance(EventsService)\n\nexport function scheduleJobInternal<TParamsSchema extends SchemaInAnyOrionForm = any>(\n options: ScheduleJobOptions<TParamsSchema>,\n nPartitions?: number,\n) {\n return eventsService.scheduleJob(options, nPartitions)\n}\n\nexport function scheduleJobsInternal<TParamsSchema extends SchemaInAnyOrionForm = any>(\n jobs: ScheduleJobsOptions<TParamsSchema>,\n nPartitions?: number,\n): Promise<ScheduleJobsResult> {\n return eventsService.scheduleJobs(jobs, nPartitions)\n}\n","import {logger} from '@orion-js/logger'\nimport {Inject, Service} from '@orion-js/services'\nimport {JobsRepo} from '../repos/JobsRepo'\nimport {ScheduleJobOptions, ScheduleJobsOptions, ScheduleJobsResult} from '../types/Events'\nimport {getNextRunDate} from './getNextRunDate'\nimport {getRandomPartition} from './partitions'\n\n@Service()\nexport class EventsService {\n @Inject(() => JobsRepo)\n private jobsRepo: JobsRepo\n\n async scheduleJob(options: ScheduleJobOptions, nPartitions?: number) {\n logger.debug('Scheduling job...', options)\n const configuredPartitions = nPartitions ?? this.jobsRepo.getJobPartitionsCount(options.name)\n\n await this.jobsRepo.scheduleJob({\n name: options.name,\n priority: options.priority || 100,\n nextRunAt: getNextRunDate(options),\n params: options.params || null,\n uniqueIdentifier: options.uniqueIdentifier,\n partition:\n configuredPartitions === undefined ? undefined : getRandomPartition(configuredPartitions),\n })\n }\n\n async scheduleJobs(jobs: ScheduleJobsOptions, nPartitions?: number): Promise<ScheduleJobsResult> {\n logger.debug(`Scheduling ${jobs.length} jobs...`)\n\n const jobRecords = jobs.map(options => {\n const configuredPartitions = nPartitions ?? this.jobsRepo.getJobPartitionsCount(options.name)\n return {\n name: options.name,\n priority: options.priority || 100,\n nextRunAt: getNextRunDate(options),\n params: options.params || null,\n uniqueIdentifier: options.uniqueIdentifier,\n partition:\n configuredPartitions === undefined ? undefined : getRandomPartition(configuredPartitions),\n }\n })\n\n return await this.jobsRepo.scheduleJobs(jobRecords)\n }\n}\n","import {CronExpressionParser} from 'cron-parser'\n\nexport type Options = {\n getNextRun?: () => Date\n runIn?: number\n runEvery?: number\n runAt?: Date\n cron?: string\n timezone?: string\n currentDate?: Date | string | number\n} & {[key: string]: any}\n\nexport const getNextRunDate = (options: Options) => {\n if (options.runIn) {\n return new Date(Date.now() + options.runIn)\n }\n\n if (options.runEvery) {\n return new Date(Date.now() + options.runEvery)\n }\n\n if (options.cron) {\n if (!options.timezone) {\n throw new Error('Cron recurrent jobs require a timezone')\n }\n\n return CronExpressionParser.parse(options.cron, {\n currentDate: options.currentDate ?? new Date(),\n tz: options.timezone,\n })\n .next()\n .toDate()\n }\n\n if (options.runAt) {\n return options.runAt\n }\n\n if (options.getNextRun) {\n return options.getNextRun()\n }\n\n return new Date()\n}\n","import {sleep} from '@orion-js/helpers'\nimport {logger} from '@orion-js/logger'\nimport {Inject, Service} from '@orion-js/services'\nimport {\n CANDIDATE_JOB_ACQUISITION_HINT,\n INITIAL_JOB_ACQUISITION_HINT,\n JobAcquisitionHint,\n JobsRepo,\n} from '../repos/JobsRepo'\nimport {JobDefinitionWithName, JobsDefinition} from '../types/JobsDefinition'\nimport {DEFAULT_MAX_TRIES_REACHED_RETENTION_MS, StartWorkersConfig} from '../types/StartConfig'\nimport {JobToRun, WorkersInstance} from '../types/Worker'\nimport {ExecuteJobConfig, Executor} from './Executor'\nimport {createShuffledPartitions, getRandomPartition, validatePartitionsCount} from './partitions'\n\nconst FILTERED_JOB_NAMES_ACQUISITION_HINT = 'byJobName' as const satisfies JobAcquisitionHint\n\ninterface TrackedExecution {\n job: JobToRun\n promise: Promise<void>\n capacityPromise: Promise<void>\n releaseCapacity: () => void\n status: 'running' | 'stale' | 'finished'\n}\n\ninterface InternalWorkersInstance extends WorkersInstance {\n activeExecutions: Map<string, TrackedExecution>\n staleExecutions: Map<string, TrackedExecution>\n runningJobsByName: Map<string, number>\n jobAcquisitionHint: JobAcquisitionHint\n jobAcquisitionHintProbeCycle: number\n hasCompletedInitialJobAcquisitionHintProbe: boolean\n pendingJobAcquisitionHint?: JobAcquisitionHint\n pendingJobAcquisitionHintWins: number\n jobAcquisitionHintProbePromise: Promise<void>\n jobAcquisitionHintProbeTimer?: ReturnType<typeof setTimeout>\n cancelJobAcquisitionHintProbeWait?: () => void\n partitionOrder: number[]\n partitionCursor: number\n partitionReconcilerPromise: Promise<void>\n partitionReconcilerTimer?: ReturnType<typeof setTimeout>\n cancelPartitionReconcilerWait?: () => void\n schedulerPromise: Promise<void>\n stopSignal: Promise<void>\n signalStop: () => void\n stopPromise?: Promise<void>\n}\n\n@Service()\nexport class WorkerService {\n private jobAcquisitionHintProbeIntervalMs = 30 * 60 * 1000\n private partitionReconcilerIntervalMs = 5 * 60 * 1000\n private partitionReconcilerJitterMs = 30 * 1000\n private partitionReconcilerBatchPauseMs = 250\n private partitionReconcilerBatchSize = 500\n\n @Inject(() => JobsRepo)\n private jobsRepo: JobsRepo\n\n @Inject(() => Executor)\n private executor: Executor\n\n getJobNames(jobs: JobsDefinition) {\n return Object.keys(jobs)\n }\n\n getJobs(jobs: JobsDefinition): JobDefinitionWithName[] {\n return Object.keys(jobs).map(name => {\n return {\n name,\n ...jobs[name],\n }\n })\n }\n\n getAvailableJobNames(\n config: StartWorkersConfig,\n workersInstance: InternalWorkersInstance,\n jobNames: string[],\n ) {\n return jobNames.filter(jobName => {\n const currentExecutions = workersInstance.runningJobsByName.get(jobName) || 0\n const job = config.jobs[jobName]\n const maxParallelExecutions =\n job.type === 'event'\n ? (job.maxParallelExecutionsPerServer ?? Number.POSITIVE_INFINITY)\n : Number.POSITIVE_INFINITY\n\n return currentExecutions < maxParallelExecutions\n })\n }\n\n reserveJobExecution(workersInstance: InternalWorkersInstance, jobName: string) {\n const currentExecutions = workersInstance.runningJobsByName.get(jobName) || 0\n workersInstance.runningJobsByName.set(jobName, currentExecutions + 1)\n }\n\n releaseJobExecution(workersInstance: InternalWorkersInstance, jobName: string) {\n const currentExecutions = workersInstance.runningJobsByName.get(jobName) || 0\n if (currentExecutions <= 1) {\n workersInstance.runningJobsByName.delete(jobName)\n return\n }\n\n workersInstance.runningJobsByName.set(jobName, currentExecutions - 1)\n }\n\n releaseExecutionCapacity(\n workersInstance: InternalWorkersInstance,\n execution: TrackedExecution,\n nextStatus: 'stale' | 'finished',\n ) {\n if (execution.status !== 'running') return\n\n execution.status = nextStatus\n workersInstance.activeExecutions.delete(execution.job.executionId)\n this.releaseJobExecution(workersInstance, execution.job.name)\n execution.releaseCapacity()\n\n if (nextStatus === 'stale') {\n workersInstance.staleExecutions.set(execution.job.executionId, execution)\n }\n }\n\n startExecution(\n config: ExecuteJobConfig,\n workersInstance: InternalWorkersInstance,\n jobToRun: JobToRun,\n ) {\n let releaseCapacity!: () => void\n const capacityPromise = new Promise<void>(resolve => {\n releaseCapacity = resolve\n })\n\n const execution: TrackedExecution = {\n job: jobToRun,\n promise: Promise.resolve(),\n capacityPromise,\n releaseCapacity,\n status: 'running',\n }\n\n this.reserveJobExecution(workersInstance, jobToRun.name)\n workersInstance.activeExecutions.set(jobToRun.executionId, execution)\n\n logger.debug(`Starting job execution \"${jobToRun.executionId}\"`, jobToRun)\n\n const executionPromise = this.executor.executeJob(config, jobToRun, () => {\n this.releaseExecutionCapacity(workersInstance, execution, 'stale')\n })\n execution.promise = executionPromise\n\n void executionPromise\n .catch(error => {\n logger.error(`Unhandled error executing job \"${jobToRun.name}\"`, {error})\n })\n .finally(() => {\n if (execution.status === 'running') {\n this.releaseExecutionCapacity(workersInstance, execution, 'finished')\n } else if (execution.status === 'stale') {\n workersInstance.staleExecutions.delete(jobToRun.executionId)\n }\n })\n }\n\n async waitForPollOrStop(config: StartWorkersConfig, workersInstance: InternalWorkersInstance) {\n await Promise.race([sleep(config.pollInterval), workersInstance.stopSignal])\n }\n\n async waitForCapacityOrStop(workersInstance: InternalWorkersInstance) {\n const capacityPromises = Array.from(\n workersInstance.activeExecutions.values(),\n execution => execution.capacityPromise,\n )\n\n if (capacityPromises.length === 0) return\n await Promise.race([...capacityPromises, workersInstance.stopSignal])\n }\n\n getNextPartition(config: StartWorkersConfig, workersInstance: InternalWorkersInstance) {\n const partition = workersInstance.partitionOrder[workersInstance.partitionCursor]\n workersInstance.partitionCursor++\n\n if (workersInstance.partitionCursor >= config.nPartitions) {\n workersInstance.partitionOrder = createShuffledPartitions(config.nPartitions)\n workersInstance.partitionCursor = 0\n }\n\n return partition\n }\n\n async runSchedulerLoop(config: StartWorkersConfig, workersInstance: InternalWorkersInstance) {\n const jobNames = this.getJobNames(config.jobs)\n const executeConfig: ExecuteJobConfig = {\n jobs: config.jobs,\n maxTries: config.maxTries,\n maxTriesReachedRetentionMs: config.maxTriesReachedRetentionMs,\n onMaxTriesReached: config.onMaxTriesReached,\n ...(config.executionGuard\n ? {\n executionGuard: config.executionGuard,\n executionGuardRetryDelayMs: Math.max(config.pollInterval, 1_000),\n }\n : {}),\n }\n\n logger.debug(`Running scheduler loop for jobs \"${jobNames.join(', ')}\"...`)\n let consecutivePartitionMisses = 0\n\n while (workersInstance.running) {\n let didMiss = false\n let allJobNamesAtCapacity = false\n\n try {\n while (workersInstance.activeExecutions.size < config.workersCount) {\n const availableJobNames = this.getAvailableJobNames(config, workersInstance, jobNames)\n\n if (availableJobNames.length === 0) {\n allJobNamesAtCapacity = workersInstance.activeExecutions.size > 0\n break\n }\n\n const jobAcquisitionHint =\n availableJobNames.length < jobNames.length\n ? FILTERED_JOB_NAMES_ACQUISITION_HINT\n : workersInstance.jobAcquisitionHint\n const partition = this.getNextPartition(config, workersInstance)\n const jobToRun = await this.jobsRepo.getJobAndLock(\n availableJobNames,\n config.defaultLockTime,\n jobAcquisitionHint,\n partition,\n )\n\n if (!jobToRun) {\n consecutivePartitionMisses++\n logger.debug(`No job to run in partition ${partition}`)\n if (consecutivePartitionMisses >= config.nPartitions) {\n consecutivePartitionMisses = 0\n didMiss = true\n break\n }\n continue\n }\n\n consecutivePartitionMisses = 0\n // An acquisition already in flight when stop() is called is considered committed.\n this.startExecution(executeConfig, workersInstance, jobToRun)\n if (!workersInstance.running) break\n }\n } catch (error) {\n logger.error('Error in job scheduler.', {error})\n consecutivePartitionMisses = 0\n didMiss = true\n }\n\n if (!workersInstance.running) return\n\n const concurrencyIsFull =\n workersInstance.activeExecutions.size >= config.workersCount &&\n workersInstance.activeExecutions.size > 0\n\n if (concurrencyIsFull || allJobNamesAtCapacity) {\n await this.waitForCapacityOrStop(workersInstance)\n } else if (didMiss || workersInstance.activeExecutions.size === 0) {\n await this.waitForPollOrStop(config, workersInstance)\n }\n }\n }\n\n getOtherJobAcquisitionHint(hint: JobAcquisitionHint): JobAcquisitionHint {\n return hint === INITIAL_JOB_ACQUISITION_HINT\n ? CANDIDATE_JOB_ACQUISITION_HINT\n : INITIAL_JOB_ACQUISITION_HINT\n }\n\n getMedian(values: number[]): number {\n const sortedValues = [...values].sort((left, right) => left - right)\n return sortedValues[Math.floor(sortedValues.length / 2)]\n }\n\n resetPendingJobAcquisitionHint(workersInstance: InternalWorkersInstance) {\n workersInstance.pendingJobAcquisitionHint = undefined\n workersInstance.pendingJobAcquisitionHintWins = 0\n }\n\n async runJobAcquisitionHintProbe(\n config: StartWorkersConfig,\n workersInstance: InternalWorkersInstance,\n ) {\n const jobNames = this.getJobNames(config.jobs)\n if (jobNames.length === 0 || !workersInstance.running) return\n\n const byHint: Record<JobAcquisitionHint, number[]> = {\n [INITIAL_JOB_ACQUISITION_HINT]: [],\n [CANDIDATE_JOB_ACQUISITION_HINT]: [],\n }\n const startsWithInitialHint = workersInstance.jobAcquisitionHintProbeCycle % 2 === 0\n const firstHint = startsWithInitialHint\n ? INITIAL_JOB_ACQUISITION_HINT\n : CANDIDATE_JOB_ACQUISITION_HINT\n const secondHint = this.getOtherJobAcquisitionHint(firstHint)\n workersInstance.jobAcquisitionHintProbeCycle++\n\n try {\n for (let sample = 0; sample < 3; sample++) {\n const partition = getRandomPartition(config.nPartitions)\n for (const hint of [firstHint, secondHint]) {\n if (!workersInstance.running) return\n const executionTimeMillis = await this.jobsRepo.getJobAcquisitionExecutionTime(\n jobNames,\n hint,\n partition,\n )\n if (!workersInstance.running) return\n byHint[hint].push(executionTimeMillis)\n }\n }\n } catch (error) {\n this.resetPendingJobAcquisitionHint(workersInstance)\n if (workersInstance.running) {\n logger.warn('Job acquisition hint probe failed; keeping the current hint.', {error})\n }\n return\n }\n\n const currentHint = workersInstance.jobAcquisitionHint\n const otherHint = this.getOtherJobAcquisitionHint(currentHint)\n const currentMedian = this.getMedian(byHint[currentHint])\n const otherMedian = this.getMedian(byHint[otherHint])\n const winner = otherMedian < currentMedian ? otherHint : currentHint\n\n if (!workersInstance.hasCompletedInitialJobAcquisitionHintProbe) {\n workersInstance.hasCompletedInitialJobAcquisitionHintProbe = true\n workersInstance.jobAcquisitionHint = winner\n this.resetPendingJobAcquisitionHint(workersInstance)\n logger.info(`Selected job acquisition hint \"${winner}\" after startup probe.`)\n return\n }\n\n if (winner === currentHint) {\n this.resetPendingJobAcquisitionHint(workersInstance)\n logger.debug(`Keeping job acquisition hint \"${currentHint}\" after probe.`)\n return\n }\n\n if (workersInstance.pendingJobAcquisitionHint === winner) {\n workersInstance.pendingJobAcquisitionHintWins++\n } else {\n workersInstance.pendingJobAcquisitionHint = winner\n workersInstance.pendingJobAcquisitionHintWins = 1\n }\n\n if (workersInstance.pendingJobAcquisitionHintWins < 2) {\n logger.debug(\n `Keeping job acquisition hint \"${currentHint}\"; \"${winner}\" has one consecutive probe win.`,\n )\n return\n }\n\n workersInstance.jobAcquisitionHint = winner\n this.resetPendingJobAcquisitionHint(workersInstance)\n logger.info(`Changed job acquisition hint from \"${currentHint}\" to \"${winner}\".`)\n }\n\n async waitForNextJobAcquisitionHintProbe(workersInstance: InternalWorkersInstance) {\n await new Promise<void>(resolve => {\n let resolved = false\n const finishWait = () => {\n if (resolved) return\n resolved = true\n clearTimeout(workersInstance.jobAcquisitionHintProbeTimer)\n workersInstance.jobAcquisitionHintProbeTimer = undefined\n workersInstance.cancelJobAcquisitionHintProbeWait = undefined\n resolve()\n }\n\n workersInstance.jobAcquisitionHintProbeTimer = setTimeout(\n finishWait,\n this.jobAcquisitionHintProbeIntervalMs,\n )\n workersInstance.cancelJobAcquisitionHintProbeWait = finishWait\n })\n }\n\n async runJobAcquisitionHintProbeLoop(\n config: StartWorkersConfig,\n workersInstance: InternalWorkersInstance,\n ) {\n if (this.getJobNames(config.jobs).length === 0) return\n\n while (workersInstance.running) {\n await this.runJobAcquisitionHintProbe(config, workersInstance)\n if (!workersInstance.running) return\n await this.waitForNextJobAcquisitionHintProbe(workersInstance)\n }\n }\n\n async reconcilePartitionBatch(config: StartWorkersConfig) {\n // Some embedders replace the repository in isolated scheduler tests.\n if (typeof this.jobsRepo.reconcilePartitions !== 'function') return 0\n\n try {\n return await this.jobsRepo.reconcilePartitions({\n jobNames: this.getJobNames(config.jobs),\n nPartitions: config.nPartitions,\n batchSize: this.partitionReconcilerBatchSize,\n })\n } catch (error) {\n logger.warn('Job partition reconciliation failed; it will be retried.', {error})\n return 0\n }\n }\n\n async waitForNextPartitionReconcile(workersInstance: InternalWorkersInstance, delayMs: number) {\n await new Promise<void>(resolve => {\n let resolved = false\n const finishWait = () => {\n if (resolved) return\n resolved = true\n clearTimeout(workersInstance.partitionReconcilerTimer)\n workersInstance.partitionReconcilerTimer = undefined\n workersInstance.cancelPartitionReconcilerWait = undefined\n resolve()\n }\n\n workersInstance.partitionReconcilerTimer = setTimeout(finishWait, delayMs)\n workersInstance.cancelPartitionReconcilerWait = finishWait\n })\n }\n\n async runPartitionReconcilerLoop(\n config: StartWorkersConfig,\n workersInstance: InternalWorkersInstance,\n initialReconcilePromise: Promise<number>,\n ) {\n let modifiedCount = await initialReconcilePromise\n\n while (workersInstance.running) {\n const didFillBatch = modifiedCount >= this.partitionReconcilerBatchSize\n const delayMs = didFillBatch\n ? this.partitionReconcilerBatchPauseMs\n : this.partitionReconcilerIntervalMs +\n Math.floor(Math.random() * (this.partitionReconcilerJitterMs + 1))\n\n await this.waitForNextPartitionReconcile(workersInstance, delayMs)\n if (!workersInstance.running) return\n modifiedCount = await this.reconcilePartitionBatch(config)\n }\n }\n\n createWorkersInstanceDefinition(config: StartWorkersConfig): InternalWorkersInstance {\n let signalStop!: () => void\n const stopSignal = new Promise<void>(resolve => {\n signalStop = resolve\n })\n\n const workersInstance: InternalWorkersInstance = {\n running: true,\n workersCount: config.workersCount,\n activeExecutions: new Map(),\n staleExecutions: new Map(),\n runningJobsByName: new Map(),\n jobAcquisitionHint: INITIAL_JOB_ACQUISITION_HINT,\n jobAcquisitionHintProbeCycle: 0,\n hasCompletedInitialJobAcquisitionHintProbe: false,\n pendingJobAcquisitionHintWins: 0,\n partitionOrder: createShuffledPartitions(config.nPartitions),\n partitionCursor: 0,\n jobAcquisitionHintProbePromise: Promise.resolve(),\n partitionReconcilerPromise: Promise.resolve(),\n schedulerPromise: Promise.resolve(),\n stopSignal,\n signalStop,\n get runningExecutions() {\n return this.activeExecutions.size\n },\n stop: async () => {\n if (workersInstance.stopPromise) return workersInstance.stopPromise\n\n workersInstance.stopPromise = (async () => {\n logger.info('Stopping job scheduler...')\n workersInstance.running = false\n workersInstance.signalStop()\n workersInstance.cancelJobAcquisitionHintProbeWait?.()\n workersInstance.cancelPartitionReconcilerWait?.()\n\n await Promise.all([\n workersInstance.schedulerPromise,\n workersInstance.jobAcquisitionHintProbePromise,\n workersInstance.partitionReconcilerPromise,\n ])\n\n const activeCapacity = Array.from(\n workersInstance.activeExecutions.values(),\n execution => execution.capacityPromise,\n )\n await Promise.all(activeCapacity)\n })()\n\n return workersInstance.stopPromise\n },\n }\n\n return workersInstance\n }\n\n async ensureRecords(config: StartWorkersConfig) {\n const jobs = this.getJobs(config.jobs)\n\n await Promise.all(\n jobs\n .filter(job => job.type === 'recurrent')\n .map(async job => {\n logger.debug(`Ensuring records for job \"${job.name}\"...`)\n await this.jobsRepo.ensureJobRecord(job, getRandomPartition(config.nPartitions))\n }),\n )\n }\n\n async runScheduler(config: StartWorkersConfig, workersInstance: InternalWorkersInstance) {\n logger.debug('Will ensure maxTriesReached retention and TTL index')\n void this.jobsRepo\n .ensureMaxTriesReachedRetention(config.maxTriesReachedRetentionMs)\n .catch(error => logger.error('Error ensuring maxTriesReached retention', {error}))\n\n logger.debug('Will ensure records for recurrent jobs')\n await this.ensureRecords(config)\n\n logger.info(`Starting job scheduler with concurrency ${config.workersCount}`)\n await this.runSchedulerLoop(config, workersInstance)\n }\n\n /**\n * Starts one job scheduler with the provided concurrency configuration.\n * @param userConfig - Configuration for the scheduler. Required field: jobs\n */\n startWorkers(userConfig: StartWorkersConfig): WorkersInstance {\n const maxTriesReachedRetentionMs =\n userConfig.maxTriesReachedRetentionMs === undefined\n ? DEFAULT_MAX_TRIES_REACHED_RETENTION_MS\n : userConfig.maxTriesReachedRetentionMs\n\n if (\n maxTriesReachedRetentionMs !== null &&\n (!Number.isFinite(maxTriesReachedRetentionMs) || maxTriesReachedRetentionMs < 0)\n ) {\n throw new Error('maxTriesReachedRetentionMs must be null, zero, or a positive number')\n }\n\n const nPartitions = userConfig.nPartitions ?? 1\n validatePartitionsCount(nPartitions)\n\n const config: StartWorkersConfig = {\n pollInterval: 3000,\n workersCount: 4,\n defaultLockTime: 30 * 1000,\n ...userConfig,\n nPartitions,\n maxTriesReachedRetentionMs,\n }\n\n setNameToJobs(config.jobs, config.nPartitions)\n this.jobsRepo.configureJobPartitions?.(this.getJobNames(config.jobs), config.nPartitions)\n\n const workersInstance = this.createWorkersInstanceDefinition(config)\n logger.debug('Starting job scheduler', config)\n\n workersInstance.jobAcquisitionHintProbePromise = this.runJobAcquisitionHintProbeLoop(\n config,\n workersInstance,\n )\n\n const initialReconcilePromise = this.reconcilePartitionBatch(config)\n workersInstance.partitionReconcilerPromise = this.runPartitionReconcilerLoop(\n config,\n workersInstance,\n initialReconcilePromise,\n )\n\n workersInstance.schedulerPromise = this.runScheduler(config, workersInstance).catch(error => {\n workersInstance.running = false\n workersInstance.signalStop()\n workersInstance.cancelJobAcquisitionHintProbeWait?.()\n workersInstance.cancelPartitionReconcilerWait?.()\n logger.error('Job scheduler stopped after an unexpected error.', {error})\n })\n\n return workersInstance\n }\n}\n\nfunction setNameToJobs(jobs: JobsDefinition, nPartitions: number) {\n for (const name of Object.keys(jobs)) {\n jobs[name].jobName = name\n jobs[name].nPartitions = nPartitions\n }\n}\n","import {SpanStatusCode, trace} from '@opentelemetry/api'\nimport {logger, runWithOrionAsyncContext, updateOrionAsyncContext} from '@orion-js/logger'\nimport {Blackbox} from '@orion-js/schema'\nimport {Inject, Service} from '@orion-js/services'\nimport {JobsHistoryRepo} from '../repos/JobsHistoryRepo'\nimport {JobsRepo} from '../repos/JobsRepo'\nimport {EventJobDefinition, JobDefinition, JobsDefinition} from '../types/JobsDefinition'\nimport {WorkerExecutionGuard, WorkerExecutionGuardLease} from '../types/StartConfig'\nimport {ExecutionContext, JobToRun} from '../types/Worker'\nimport {getNextRunDate} from './getNextRunDate'\n\n/**\n * Configuration for job execution including max tries settings.\n */\nexport interface ExecuteJobConfig {\n jobs: JobsDefinition\n maxTries?: number\n maxTriesReachedRetentionMs?: number | null\n onMaxTriesReached?: (job: JobToRun) => Promise<void>\n executionGuard?: WorkerExecutionGuard\n executionGuardRetryDelayMs?: number\n}\n\n@Service()\nexport class Executor {\n @Inject(() => JobsRepo)\n private readonly jobsRepo: JobsRepo\n\n @Inject(() => JobsHistoryRepo)\n private readonly jobsHistoryRepo: JobsHistoryRepo\n\n /**\n * Determines the effective lock time for a job execution.\n * Job-specific lockTime takes precedence over the default lockTime from config.\n */\n getEffectiveLockTime(job: JobDefinition, jobToRun: JobToRun): number {\n return job.lockTime ?? jobToRun.lockTime\n }\n\n getContext(\n job: JobDefinition,\n jobToRun: JobToRun,\n onStale: () => void,\n isExecutionActive: () => boolean,\n ): ExecutionContext {\n const effectiveLockTime = this.getEffectiveLockTime(job, jobToRun)\n const contextLogger = logger.addMetadata({\n jobName: jobToRun.name,\n jobId: jobToRun.jobId,\n })\n let staleTimeout: ReturnType<typeof setTimeout> | undefined\n let watchdogCleared = false\n let staleReported = false\n let pendingExtraTime: number | undefined\n let renewalRunning = false\n let renewalPromise: Promise<void> | undefined\n\n const clearCurrentStaleTimeout = () => {\n if (staleTimeout === undefined) return\n clearTimeout(staleTimeout)\n staleTimeout = undefined\n }\n\n const reportStale = () => {\n if (staleReported) return\n staleReported = true\n watchdogCleared = true\n pendingExtraTime = undefined\n clearCurrentStaleTimeout()\n onStale()\n }\n\n const armStaleTimeout = (lockedUntil: number) => {\n if (watchdogCleared || staleReported || !isExecutionActive()) return\n\n clearCurrentStaleTimeout()\n staleTimeout = setTimeout(\n () => {\n staleTimeout = undefined\n reportStale()\n },\n Math.max(0, lockedUntil - Date.now()),\n )\n staleTimeout.unref?.()\n }\n\n const runRenewals = async () => {\n try {\n while (pendingExtraTime !== undefined) {\n const extraTime = pendingExtraTime\n pendingExtraTime = undefined\n\n if (watchdogCleared || staleReported || !isExecutionActive()) {\n clearCurrentStaleTimeout()\n return\n }\n\n clearCurrentStaleTimeout()\n\n // JobsRepo calculates lockedUntil synchronously when this call starts. Keep the local\n // watchdog on that same deadline instead of adding Mongo response latency to the lock.\n const lockedUntil = Date.now() + extraTime\n let didExtend = false\n try {\n didExtend = await this.jobsRepo.extendLockTime(\n jobToRun.jobId,\n extraTime,\n jobToRun.lockId,\n )\n } catch (error) {\n reportStale()\n throw error\n }\n\n if (!didExtend) {\n reportStale()\n return\n }\n\n if (watchdogCleared || staleReported || !isExecutionActive()) {\n pendingExtraTime = undefined\n clearCurrentStaleTimeout()\n return\n }\n\n armStaleTimeout(lockedUntil)\n }\n } finally {\n // Clear the single-flight state before the promise settles so a pulse queued in the same\n // microtask checkpoint cannot attach itself to a renewal loop that has already stopped.\n renewalRunning = false\n renewalPromise = undefined\n }\n }\n\n armStaleTimeout(Date.now() + effectiveLockTime)\n\n return {\n definition: job,\n record: jobToRun,\n tries: jobToRun.tries || 0,\n clearStaleTimeout: () => {\n watchdogCleared = true\n pendingExtraTime = undefined\n clearCurrentStaleTimeout()\n },\n extendLockTime: (extraTime: number) => {\n if (watchdogCleared || staleReported || !isExecutionActive()) {\n contextLogger.warn(`Will not extend lock for stale execution \"${jobToRun.executionId}\"`)\n return Promise.resolve()\n }\n\n // One pending duration coalesces any number of pulses while Mongo is busy. Keeping the\n // longest duration prevents a shorter coalesced pulse from reducing the intended lock.\n pendingExtraTime = Math.max(pendingExtraTime ?? extraTime, extraTime)\n\n if (!renewalRunning) {\n renewalRunning = true\n renewalPromise = runRenewals()\n }\n\n return renewalPromise ?? Promise.resolve()\n },\n logger: contextLogger,\n }\n }\n\n getJobDefinition(jobToRun: JobToRun, jobs: JobsDefinition) {\n const job = jobs[jobToRun.name]\n\n if (jobToRun.type !== job.type) {\n logger.warn(\n `Job record \"${jobToRun.name}\" is \"${jobToRun.type}\" but definition is \"${job.type}\"`,\n )\n return\n }\n\n return job\n }\n\n /**\n * Determines the effective max tries for an event job.\n * Job-specific maxTries takes precedence over the global maxTries from config.\n */\n getEffectiveMaxTries(job: EventJobDefinition, globalMaxTries?: number): number | undefined {\n return job.maxTries ?? globalMaxTries\n }\n\n /**\n * Handles when a job has reached its maximum retry attempts.\n * Marks the job in the database and invokes the onMaxTriesReached callback when provided.\n */\n async handleMaxTriesReached(\n jobToRun: JobToRun,\n retentionMs?: number | null,\n onMaxTriesReached?: (job: JobToRun) => Promise<void>,\n ) {\n const jobLogger = logger.addMetadata({\n jobName: jobToRun.name,\n jobId: jobToRun.jobId,\n })\n\n jobLogger.warn(\n `Job \"${jobToRun.name}\" has exceeded max tries (${jobToRun.tries}). Marking as maxTriesReached.`,\n )\n const didMark = await this.jobsRepo.markJobAsMaxTriesReached(\n jobToRun.jobId,\n retentionMs,\n jobToRun.lockId,\n )\n\n if (!didMark) {\n jobLogger.warn(`Could not mark job \"${jobToRun.name}\" because its lock is no longer owned`)\n return false\n }\n\n if (!onMaxTriesReached) return true\n\n // Invoke the callback to notify administrators\n try {\n await onMaxTriesReached(jobToRun)\n } catch (callbackError) {\n jobLogger.error(`Error in onMaxTriesReached callback for job \"${jobToRun.name}\"`, {\n error: callbackError,\n })\n }\n\n return true\n }\n\n async onError(error: unknown, job: JobDefinition, jobToRun: JobToRun, context: ExecutionContext) {\n // Helper to schedule next run for recurrent jobs (used when dismissing)\n const scheduleRecurrent = async () => {\n if (job.type === 'recurrent') {\n return this.jobsRepo.scheduleNextRun({\n jobId: jobToRun.jobId,\n nextRunAt: getNextRunDate(job),\n resetTries: true,\n priority: job.priority,\n lockId: jobToRun.lockId,\n })\n }\n return true\n }\n\n const handleRetry = async (nextRunAt: Date) => {\n return this.jobsRepo.scheduleNextRun({\n jobId: jobToRun.jobId,\n nextRunAt,\n resetTries: false,\n priority: job.type === 'recurrent' ? job.priority : jobToRun.priority,\n lockId: jobToRun.lockId,\n })\n }\n\n if (!job.onError) {\n context.logger.error(`Error executing job \"${jobToRun.name}\"`, {error})\n\n return scheduleRecurrent()\n }\n\n context.logger.info(`Error executing job \"${jobToRun.name}\"`, {error})\n const result = await job.onError(\n error instanceof Error ? error : new Error(String(error)),\n jobToRun.params,\n context,\n )\n\n if (result.action === 'dismiss') {\n return scheduleRecurrent()\n }\n\n if (result.action === 'retry') {\n return handleRetry(getNextRunDate(result))\n }\n\n return true\n }\n\n async saveExecution(options: {\n startedAt: Date\n status: 'stale' | 'error' | 'success'\n errorMessage?: string\n result?: Blackbox\n job: JobDefinition\n jobToRun: JobToRun\n }) {\n const {startedAt, status, errorMessage, result, job, jobToRun} = options\n const endedAt = new Date()\n\n if (job.saveExecutionsFor !== 0) {\n const oneWeek = 1000 * 60 * 60 * 24 * 7\n const saveExecutionsFor = job.saveExecutionsFor || oneWeek\n await this.jobsHistoryRepo.saveExecution({\n jobId: jobToRun.jobId,\n executionId: jobToRun.executionId,\n jobName: jobToRun.name,\n type: jobToRun.type,\n priority: jobToRun.priority,\n tries: jobToRun.tries,\n uniqueIdentifier: jobToRun.uniqueIdentifier,\n startedAt,\n endedAt,\n duration: endedAt.getTime() - startedAt.getTime(),\n expiresAt: new Date(Date.now() + saveExecutionsFor),\n status,\n errorMessage,\n params: jobToRun.params,\n result,\n })\n }\n }\n\n async afterExecutionSuccess(job: JobDefinition, jobToRun: JobToRun, context: ExecutionContext) {\n if (job.type === 'recurrent') {\n context.logger.debug(`Scheduling next run for recurrent job \"${jobToRun.name}\"`)\n return this.jobsRepo.scheduleNextRun({\n jobId: jobToRun.jobId,\n nextRunAt: getNextRunDate(job),\n resetTries: true,\n priority: job.priority,\n lockId: jobToRun.lockId,\n })\n }\n if (job.type === 'event') {\n context.logger.debug(`Removing event job after success \"${jobToRun.name}\"`)\n return this.jobsRepo.deleteEventJob(jobToRun.jobId, jobToRun.lockId)\n }\n return false\n }\n\n async handleExecutionGuardAcquisitionFailure(\n error: unknown,\n config: ExecuteJobConfig,\n jobToRun: JobToRun,\n context: ExecutionContext,\n ) {\n context.logger.error(`Error acquiring execution guard for job \"${jobToRun.name}\"`, {error})\n\n const nextRunAt = new Date(Date.now() + (config.executionGuardRetryDelayMs ?? 1_000))\n try {\n const didReschedule = await this.jobsRepo.rescheduleAfterExecutionGuardAcquisitionFailure(\n jobToRun.jobId,\n jobToRun.lockId,\n nextRunAt,\n )\n if (!didReschedule) {\n context.logger.warn(\n `Could not requeue job \"${jobToRun.name}\" after execution guard acquisition failed because its lock is no longer owned`,\n )\n }\n } catch (rescheduleError) {\n context.logger.error(\n `Error requeueing job \"${jobToRun.name}\" after execution guard acquisition failed`,\n {error: rescheduleError},\n )\n }\n }\n\n async releaseExecutionGuardLease(\n lease: WorkerExecutionGuardLease,\n jobToRun: JobToRun,\n context: ExecutionContext,\n ) {\n try {\n await lease.release()\n } catch (error) {\n context.logger.error(`Error releasing execution guard for job \"${jobToRun.name}\"`, {error})\n }\n }\n\n async runGuardedResolver(\n job: JobDefinition,\n jobToRun: JobToRun,\n context: ExecutionContext,\n lease: WorkerExecutionGuardLease,\n ) {\n try {\n return await job.resolve(jobToRun.params, context)\n } finally {\n context.clearStaleTimeout()\n await this.releaseExecutionGuardLease(lease, jobToRun, context)\n }\n }\n\n async executeJob(config: ExecuteJobConfig, jobToRun: JobToRun, onExecutionStale: () => void) {\n const job = this.getJobDefinition(jobToRun, config.jobs)\n if (!job) return\n\n if (job.type === 'event') {\n const effectiveMaxTries = this.getEffectiveMaxTries(job, config.maxTries)\n if (typeof effectiveMaxTries === 'number' && jobToRun.tries > effectiveMaxTries) {\n await this.handleMaxTriesReached(\n jobToRun,\n config.maxTriesReachedRetentionMs,\n config.onMaxTriesReached,\n )\n return\n }\n }\n\n // If job has a custom lockTime different from the default, update the database lock\n const effectiveLockTime = this.getEffectiveLockTime(job, jobToRun)\n if (effectiveLockTime !== jobToRun.lockTime) {\n const didUpdateLock = await this.jobsRepo.updateLockTime(\n jobToRun.jobId,\n effectiveLockTime,\n jobToRun.lockId,\n )\n if (!didUpdateLock) {\n logger.warn(`Will not execute job \"${jobToRun.name}\" because its lock is no longer owned`)\n return\n }\n }\n\n const tracer = trace.getTracer('orionjs.dogs', '1.0')\n\n await tracer.startActiveSpan(`job.${jobToRun.name}.${jobToRun.executionId}`, async span => {\n try {\n const startedAt = new Date()\n let executionStatus: 'running' | 'stale' = 'running'\n let staleHandlingPromise: Promise<void> | undefined\n let context: ExecutionContext\n\n const markAsStale = () => {\n if (executionStatus === 'stale') return staleHandlingPromise\n\n executionStatus = 'stale'\n context.clearStaleTimeout()\n\n staleHandlingPromise = (async () => {\n context.logger.warn(`Job \"${jobToRun.name}\" is stale`)\n\n if (job.onStale) {\n void Promise.resolve(job.onStale(jobToRun.params, context)).catch(error => {\n context.logger.error(`Error in onStale callback for job \"${jobToRun.name}\"`, {\n error,\n })\n })\n }\n\n try {\n await this.jobsRepo.setJobRecordPriority(jobToRun.jobId, 0, jobToRun.lockId)\n } catch (error) {\n context.logger.error(`Error lowering priority for stale job \"${jobToRun.name}\"`, {\n error,\n })\n } finally {\n // Preserve the current ordering guarantee: a stale retry only becomes eligible for\n // local capacity after its priority has been lowered.\n onExecutionStale()\n }\n\n await this.saveExecution({\n startedAt,\n status: 'stale',\n result: null,\n errorMessage: null,\n job,\n jobToRun,\n })\n })().catch(error => {\n context.logger.error('Error handling stale execution', {error})\n })\n\n return staleHandlingPromise\n }\n\n context = this.getContext(\n job,\n jobToRun,\n () => void markAsStale(),\n () => executionStatus === 'running',\n )\n\n const extraContext = {\n controllerType: 'job' as const,\n jobName: jobToRun.name,\n jobId: jobToRun.jobId,\n params: jobToRun.params,\n }\n\n await runWithOrionAsyncContext(extraContext, async () => {\n let executionGuardLease: WorkerExecutionGuardLease | undefined\n if (config.executionGuard) {\n updateOrionAsyncContext({\n jobName: jobToRun.name,\n jobId: jobToRun.jobId,\n params: jobToRun.params,\n })\n\n try {\n executionGuardLease = await config.executionGuard.acquire(jobToRun)\n } catch (error) {\n context.clearStaleTimeout()\n await this.handleExecutionGuardAcquisitionFailure(error, config, jobToRun, context)\n if (executionStatus === 'stale') await staleHandlingPromise\n return\n }\n\n if (executionStatus === 'stale') {\n await staleHandlingPromise\n await this.releaseExecutionGuardLease(executionGuardLease, jobToRun, context)\n return\n }\n }\n\n try {\n if (!config.executionGuard) {\n // Preserve the unguarded execution path, including its existing error handling.\n updateOrionAsyncContext({\n jobName: jobToRun.name,\n jobId: jobToRun.jobId,\n params: jobToRun.params,\n })\n }\n\n const result = executionGuardLease\n ? await this.runGuardedResolver(job, jobToRun, context, executionGuardLease)\n : await job.resolve(jobToRun.params, context)\n context.clearStaleTimeout()\n\n if (executionStatus === 'stale') {\n await staleHandlingPromise\n context.logger.warn(\n `Ignoring late success from stale execution \"${jobToRun.executionId}\"`,\n )\n return\n }\n\n const stillOwnsJob = await this.afterExecutionSuccess(job, jobToRun, context)\n if (!stillOwnsJob) {\n await markAsStale()\n return\n }\n\n void this.saveExecution({\n startedAt,\n status: 'success',\n result: result || null,\n errorMessage: null,\n job,\n jobToRun,\n }).catch(error => {\n context.logger.error('Error saving successful execution history', {error})\n })\n } catch (error) {\n context.clearStaleTimeout()\n\n if (executionStatus === 'stale') {\n await staleHandlingPromise\n context.logger.warn(\n `Ignoring late error from stale execution \"${jobToRun.executionId}\"`,\n {error},\n )\n return\n }\n\n const stillOwnsJob = await this.onError(error, job, jobToRun, context)\n if (!stillOwnsJob) {\n await markAsStale()\n return\n }\n\n void this.saveExecution({\n startedAt,\n status: 'error',\n result: null,\n errorMessage: (error as Error).message,\n job,\n jobToRun,\n }).catch(saveError => {\n context.logger.error('Error saving failed execution history', {error: saveError})\n })\n }\n })\n } catch (error) {\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: (error as Error).message,\n })\n throw error\n } finally {\n span.end()\n }\n })\n }\n}\n","import {cleanAndValidate, SchemaInAnyOrionForm} from '@orion-js/schema'\nimport {CronExpressionParser} from 'cron-parser'\nimport parse from 'parse-duration'\nimport {ScheduleJobsResult} from '..'\nimport {scheduleJobInternal, scheduleJobsInternal} from '../schedule'\nimport {ScheduleJobOptionsWithoutName} from '../types/Events'\nimport {\n CreateEventJobOptions,\n CreateJobOptions,\n CreateRecurrentJobOptions,\n EventJobDefinition,\n JobDefinition,\n RecurrentJobDefinition,\n} from '../types/JobsDefinition'\n\nexport function createEventJob<TParamsSchema extends SchemaInAnyOrionForm>(\n options: CreateEventJobOptions<TParamsSchema>,\n): EventJobDefinition<TParamsSchema> {\n const jobDefinition: EventJobDefinition<TParamsSchema> = {\n ...options,\n type: 'event',\n schedule: null,\n scheduleJobs: null,\n }\n\n jobDefinition.schedule = async (\n scheduleOptions: ScheduleJobOptionsWithoutName<TParamsSchema>,\n ) => {\n if (!jobDefinition.jobName) {\n throw new Error('This job has not been registered in the workers')\n }\n\n const params = jobDefinition.params\n ? await cleanAndValidate(jobDefinition.params, scheduleOptions.params)\n : scheduleOptions.params\n\n return await scheduleJobInternal(\n {\n ...scheduleOptions,\n name: jobDefinition.jobName,\n params,\n },\n jobDefinition.nPartitions,\n )\n }\n\n jobDefinition.scheduleJobs = async (\n jobs: Array<ScheduleJobOptionsWithoutName<TParamsSchema>>,\n ): Promise<ScheduleJobsResult> => {\n if (!jobDefinition.jobName) {\n throw new Error('This job has not been registered in the workers')\n }\n\n // Process all job parameters if schema validation is needed\n const processedJobs = await Promise.all(\n jobs.map(async scheduleOptions => {\n const params = jobDefinition.params\n ? await cleanAndValidate(jobDefinition.params, scheduleOptions.params)\n : scheduleOptions.params\n\n return {\n ...scheduleOptions,\n name: jobDefinition.jobName,\n params,\n }\n }),\n )\n\n return await scheduleJobsInternal(processedJobs, jobDefinition.nPartitions)\n }\n\n return jobDefinition\n}\n\nexport function createRecurrentJob(options: CreateRecurrentJobOptions): RecurrentJobDefinition {\n const recurrentOptions = {\n ...options,\n } as CreateRecurrentJobOptions & {maxTries?: number}\n\n delete recurrentOptions.maxTries\n\n if ('cron' in recurrentOptions && recurrentOptions.cron && !recurrentOptions.timezone) {\n throw new Error('Cron recurrent jobs require a timezone')\n }\n\n if ('cron' in recurrentOptions && recurrentOptions.cron) {\n CronExpressionParser.parse(recurrentOptions.cron, {tz: recurrentOptions.timezone}).next()\n }\n\n const runEvery =\n 'runEvery' in recurrentOptions\n ? typeof recurrentOptions.runEvery === 'string'\n ? parse(recurrentOptions.runEvery)\n : recurrentOptions.runEvery\n : undefined\n\n const jobDefinition: RecurrentJobDefinition = {\n ...recurrentOptions,\n priority: recurrentOptions.priority ?? 100,\n type: 'recurrent',\n runEvery,\n }\n\n return jobDefinition\n}\n\n/**\n * @deprecated Use `createEventJob` or `createRecurrentJob` instead.\n */\nexport const defineJob = (\n options: CreateJobOptions & {type: 'event' | 'recurrent'},\n): JobDefinition => {\n return options.type === 'event'\n ? createEventJob(options as any)\n : createRecurrentJob(options as any)\n}\n","import {getInstance, Service} from '@orion-js/services'\nimport {createEventJob, defineJob} from '../defineJob'\nimport type {CreateEventJobOptions, JobDefinition, RecurrentJobDefinition} from '../types'\n\n// Define metadata storage using WeakMaps\nconst serviceMetadata = new WeakMap<any, {_serviceType: string}>()\nconst jobsMetadata = new Map<any, Record<string, any>>()\nconst jobEntriesByClass = new Map<Function, Record<string, (instance: any) => any>>()\nlet pendingJobEntries: Record<string, (instance: any) => any> = {}\n\nexport function Jobs() {\n return (target: any, context: ClassDecoratorContext<any>) => {\n Service()(target, context)\n serviceMetadata.set(target, {_serviceType: 'jobs'})\n\n if (Object.keys(pendingJobEntries).length > 0) {\n jobEntriesByClass.set(target, pendingJobEntries)\n pendingJobEntries = {}\n }\n }\n}\n\nexport function RecurrentJob(): (\n method: any,\n context: ClassFieldDecoratorContext | ClassMethodDecoratorContext,\n) => any\nexport function RecurrentJob(\n options: Omit<RecurrentJobDefinition, 'resolve' | 'type'>,\n): (method: any, context: ClassMethodDecoratorContext) => any\nexport function RecurrentJob(options = {}) {\n return (method: any, context: ClassFieldDecoratorContext | ClassMethodDecoratorContext) => {\n const propertyKey = String(context.name)\n\n if (context.kind === 'method') {\n pendingJobEntries[propertyKey] = (instance: any) =>\n defineJob({\n ...options,\n type: 'recurrent',\n resolve: instance[propertyKey].bind(instance),\n })\n }\n\n if (context.kind === 'field') {\n pendingJobEntries[propertyKey] = (instance: any) => instance[propertyKey]\n }\n\n return method\n }\n}\n\nexport function EventJob(): (\n method: any,\n context: ClassFieldDecoratorContext | ClassMethodDecoratorContext,\n) => any\nexport function EventJob(\n options: Omit<CreateEventJobOptions<any>, 'resolve'>,\n): (method: any, context: ClassMethodDecoratorContext) => any\nexport function EventJob(options = {}) {\n return (method: any, context: ClassFieldDecoratorContext | ClassMethodDecoratorContext) => {\n const propertyKey = String(context.name)\n\n if (context.kind === 'method') {\n pendingJobEntries[propertyKey] = (instance: any) =>\n createEventJob({\n ...options,\n resolve: instance[propertyKey].bind(instance),\n })\n }\n\n if (context.kind === 'field') {\n pendingJobEntries[propertyKey] = (instance: any) => instance[propertyKey]\n }\n\n return method\n }\n}\n\nfunction initializeJobsIfNeeded(instance: any) {\n if (jobsMetadata.has(instance)) return\n const entries = jobEntriesByClass.get(instance.constructor) || {}\n const jobs: Record<string, any> = {}\n for (const [key, setup] of Object.entries(entries)) {\n jobs[key] = setup(instance)\n }\n jobsMetadata.set(instance, jobs)\n}\n\nexport function getServiceJobs(target: any): {\n [key: string]: JobDefinition\n} {\n const instance = getInstance(target)\n\n if (!serviceMetadata.has(instance.constructor)) {\n throw new Error('You must pass a class decorated with @Jobs to getServiceJobs')\n }\n\n const instanceMetadata = serviceMetadata.get(instance.constructor)\n if (instanceMetadata._serviceType !== 'jobs') {\n throw new Error('You must pass a class decorated with @Jobs to getServiceJobs')\n }\n\n initializeJobsIfNeeded(instance)\n\n const jobsMap = jobsMetadata.get(instance) || {}\n\n return jobsMap\n}\n"],"mappings":"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","names":["import_services","import_mongodb","import_schema","import_schema","_init","import_services","import_logger","_init","import_helpers","import_logger","import_services","import_logger","import_services","_jobsRepo_dec","_init","_jobsRepo_dec","_init","_a","_b","import_schema","import_cron_parser","parse","import_services"]}