@backstage/backend-defaults 0.18.0 → 0.18.1-next.0
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.
- package/CHANGELOG.md +18 -0
- package/dist/CreateBackend.cjs.js.map +1 -1
- package/dist/PackageDiscoveryService.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/actions/DefaultActionsService.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/actions/actionsServiceFactory.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/actionsRegistry/DefaultActionsRegistryService.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/actionsRegistry/actionFilters.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/actionsRegistry/actionsRegistryServiceFactory.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/instanceMetadata/instanceMetadataServiceFactory.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/metrics/DefaultMetricsService.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/metrics/metricsServiceFactory.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/tracing/DefaultTracingService.cjs.js.map +1 -1
- package/dist/alpha/entrypoints/tracing/tracingServiceFactory.cjs.js.map +1 -1
- package/dist/discoveryFeatureLoader.cjs.js.map +1 -1
- package/dist/entrypoints/auditor/DefaultAuditorService.cjs.js.map +1 -1
- package/dist/entrypoints/auditor/WinstonRootAuditorService.cjs.js.map +1 -1
- package/dist/entrypoints/auditor/auditorServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/auditor/utils.cjs.js.map +1 -1
- package/dist/entrypoints/auth/DefaultAuthService.cjs.js.map +1 -1
- package/dist/entrypoints/auth/JwksClient.cjs.js.map +1 -1
- package/dist/entrypoints/auth/authServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/ExternalAuthTokenHandler.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/helpers.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/jwks.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/legacy.cjs.js.map +1 -1
- package/dist/entrypoints/auth/external/static.cjs.js.map +1 -1
- package/dist/entrypoints/auth/helpers.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/PluginTokenHandler.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/DatabaseKeyStore.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/DatabasePluginKeySource.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/StaticConfigPluginKeySource.cjs.js.map +1 -1
- package/dist/entrypoints/auth/plugin/keys/createPluginKeySource.cjs.js.map +1 -1
- package/dist/entrypoints/auth/user/UserTokenHandler.cjs.js.map +1 -1
- package/dist/entrypoints/cache/CacheClient.cjs.js.map +1 -1
- package/dist/entrypoints/cache/CacheManager.cjs.js.map +1 -1
- package/dist/entrypoints/cache/cacheServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/cache/providers/infinispan/InfinispanKeyvStore.cjs.js.map +1 -1
- package/dist/entrypoints/cache/providers/infinispan/InfinispanOptionsMapper.cjs.js.map +1 -1
- package/dist/entrypoints/cache/types.cjs.js.map +1 -1
- package/dist/entrypoints/database/DatabaseManager.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/defaultNameOverride.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/mergeDatabaseConfig.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/mysql.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/postgres.cjs.js +2 -0
- package/dist/entrypoints/database/connectors/postgres.cjs.js.map +1 -1
- package/dist/entrypoints/database/connectors/sqlite3.cjs.js.map +1 -1
- package/dist/entrypoints/database/databaseServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/HostDiscovery.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/SrvResolvers.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/discoveryServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/discovery/parsing.cjs.js.map +1 -1
- package/dist/entrypoints/httpAuth/httpAuthServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/http/createAuthIntegrationRouter.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/http/createCookieAuthRefreshMiddleware.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/http/createCredentialsBarrier.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/http/createLifecycleMiddleware.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/http/createRateLimitMiddleware.cjs.js.map +1 -1
- package/dist/entrypoints/httpRouter/httpRouterServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/lifecycle/lifecycleServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/logger/loggerServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/permissions/permissionsServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootConfig/createConfigSecretEnumerator.cjs.js.map +1 -1
- package/dist/entrypoints/rootConfig/rootConfigServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootHealth/rootHealthServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/DefaultRootHttpRouter.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/createHealthRouter.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/MiddlewareFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/applyInternalErrorFilter.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/config.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/createHttpServer.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/getGeneratedCertificate.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/readCorsOptions.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/http/readHelmetOptions.cjs.js.map +1 -1
- package/dist/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootLifecycle/rootLifecycleServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootLogger/WinstonLogger.cjs.js.map +1 -1
- package/dist/entrypoints/rootLogger/config.cjs.js.map +1 -1
- package/dist/entrypoints/rootLogger/rootLoggerServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/rootLogger/types.cjs.js.map +1 -1
- package/dist/entrypoints/rootLogger/utils.cjs.js.map +1 -1
- package/dist/entrypoints/rootSystemMetadata/lib/DefaultRootSystemMetadataService.cjs.js.map +1 -1
- package/dist/entrypoints/rootSystemMetadata/rootSystemMetadataServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/database/migrateBackendTasks.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/database/tables.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/DefaultSchedulerService.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/LocalTaskWorker.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/TaskStatePoller.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/TaskWorker.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/types.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/lib/util.cjs.js.map +1 -1
- package/dist/entrypoints/scheduler/schedulerServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AwsS3UrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/AzureUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/BitbucketCloudUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/BitbucketServerUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/FetchUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GerritUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GiteaUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GithubUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GitlabUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/GoogleGcsUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/HarnessUrlReader.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/ReadUrlResponseFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/UrlReaderPredicateMux.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/UrlReaders.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ReadableArrayResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/TarArchiveResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/ZipArchiveResponse.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/tree/util.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/lib/util.cjs.js.map +1 -1
- package/dist/entrypoints/urlReader/urlReaderServiceFactory.cjs.js.map +1 -1
- package/dist/entrypoints/userInfo/CachedUserInfoService.cjs.js.map +1 -1
- package/dist/entrypoints/userInfo/DefaultUserInfoService.cjs.js.map +1 -1
- package/dist/entrypoints/userInfo/userInfoServiceFactory.cjs.js.map +1 -1
- package/dist/lib/RateLimitStoreFactory.cjs.js.map +1 -1
- package/dist/lib/escapeRegExp.cjs.js.map +1 -1
- package/dist/lib/rateLimitMiddleware.cjs.js.map +1 -1
- package/dist/package.json.cjs.js +1 -1
- package/dist/package.json.cjs.js.map +1 -1
- package/package.json +17 -17
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginTaskSchedulerImpl.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n LoggerService,\n RootLifecycleService,\n SchedulerService,\n SchedulerServiceTaskDescriptor,\n SchedulerServiceTaskFunction,\n SchedulerServiceTaskInvocationDefinition,\n SchedulerServiceTaskRunner,\n SchedulerServiceTaskScheduleDefinition,\n} from '@backstage/backend-plugin-api';\nimport { trace } from '@opentelemetry/api';\nimport {\n MetricsService,\n MetricsServiceCounter,\n MetricsServiceGauge,\n MetricsServiceHistogram,\n} from '@backstage/backend-plugin-api/alpha';\nimport { Knex } from 'knex';\nimport { Duration } from 'luxon';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { LocalTaskWorker } from './LocalTaskWorker';\nimport { TaskStatePoller } from './TaskStatePoller';\nimport { TaskWorker } from './TaskWorker';\nimport { TaskSettingsV2, TaskApiTasksResponse } from './types';\nimport { delegateAbortController, TRACER_ID, validateId } from './util';\n\nconst tracer = trace.getTracer(TRACER_ID);\n\n/**\n * Implements the actual task management.\n */\nexport class PluginTaskSchedulerImpl implements SchedulerService {\n private readonly localWorkersById = new Map<string, LocalTaskWorker>();\n private readonly globalWorkersById = new Map<string, TaskWorker>();\n private readonly allScheduledTasks: SchedulerServiceTaskDescriptor[] = [];\n private readonly shutdownInitiated: Promise<boolean>;\n\n private readonly counter: MetricsServiceCounter;\n private readonly duration: MetricsServiceHistogram;\n private readonly lastStarted: MetricsServiceGauge;\n private readonly lastCompleted: MetricsServiceGauge;\n\n private readonly pluginId: string;\n private readonly databaseFactory: () => Promise<Knex>;\n private readonly logger: LoggerService;\n private poller?: TaskStatePoller;\n\n constructor(\n pluginId: string,\n databaseFactory: () => Promise<Knex>,\n logger: LoggerService,\n metrics: MetricsService,\n rootLifecycle: RootLifecycleService,\n ) {\n this.pluginId = pluginId;\n this.databaseFactory = databaseFactory;\n this.logger = logger;\n this.counter = metrics.createCounter('backend_tasks.task.runs.count', {\n description: 'Total number of times a task has been run',\n });\n this.duration = metrics.createHistogram(\n 'backend_tasks.task.runs.duration',\n {\n description: 'Histogram of task run durations',\n unit: 'seconds',\n },\n );\n this.lastStarted = metrics.createGauge('backend_tasks.task.runs.started', {\n description: 'Epoch timestamp seconds when the task was last started',\n unit: 'seconds',\n });\n this.lastCompleted = metrics.createGauge(\n 'backend_tasks.task.runs.completed',\n {\n description: 'Epoch timestamp seconds when the task was last completed',\n unit: 'seconds',\n },\n );\n this.shutdownInitiated = new Promise(shutdownInitiated => {\n rootLifecycle.addShutdownHook(() => shutdownInitiated(true));\n });\n }\n\n async triggerTask(id: string): Promise<void> {\n const localTask = this.localWorkersById.get(id);\n if (localTask) {\n localTask.trigger();\n return;\n }\n\n const knex = await this.databaseFactory();\n await TaskWorker.trigger(knex, id);\n }\n\n async cancelTask(id: string): Promise<void> {\n const localTask = this.localWorkersById.get(id);\n if (localTask) {\n localTask.cancel();\n return;\n }\n\n const knex = await this.databaseFactory();\n await TaskWorker.cancel(knex, id);\n }\n\n async scheduleTask(\n task: SchedulerServiceTaskScheduleDefinition &\n SchedulerServiceTaskInvocationDefinition,\n ): Promise<void> {\n validateId(task.id);\n const scope = task.scope ?? 'global';\n\n const settings: TaskSettingsV2 = {\n version: 2,\n cadence: parseDuration(task.frequency),\n initialDelayDuration:\n task.initialDelay && parseDuration(task.initialDelay),\n timeoutAfterDuration: parseDuration(task.timeout),\n };\n\n // Delegated abort controller that will abort either when the provided\n // controller aborts, or when a root lifecycle shutdown happens\n const abortController = delegateAbortController(task.signal);\n this.shutdownInitiated.then(() => abortController.abort());\n\n if (scope === 'global') {\n const knex = await this.databaseFactory();\n\n if (!this.poller) {\n this.poller = new TaskStatePoller({\n knex,\n logger: this.logger.child({ type: 'taskStatePoller' }),\n });\n }\n\n const worker = new TaskWorker(\n task.id,\n this.instrumentedFunction(task, scope),\n knex,\n this.logger.child({ task: task.id }),\n this.poller,\n );\n await worker.start(settings, { signal: abortController.signal });\n this.globalWorkersById.set(task.id, worker);\n } else {\n const worker = new LocalTaskWorker(\n task.id,\n this.instrumentedFunction(task, scope),\n this.logger.child({ task: task.id }),\n );\n worker.start(settings, { signal: abortController.signal });\n this.localWorkersById.set(task.id, worker);\n }\n\n this.allScheduledTasks.push({\n id: task.id,\n scope: scope,\n settings: settings,\n });\n }\n\n createScheduledTaskRunner(\n schedule: SchedulerServiceTaskScheduleDefinition,\n ): SchedulerServiceTaskRunner {\n return {\n run: async task => {\n await this.scheduleTask({ ...task, ...schedule });\n },\n };\n }\n\n async getScheduledTasks(): Promise<SchedulerServiceTaskDescriptor[]> {\n return this.allScheduledTasks;\n }\n\n getRouter(): express.Router {\n const router = Router();\n\n router.get('/.backstage/scheduler/v1/tasks', async (_, res) => {\n const globalState = await TaskWorker.taskStates(\n await this.databaseFactory(),\n );\n\n const tasks = new Array<TaskApiTasksResponse>();\n for (const task of this.allScheduledTasks) {\n tasks.push({\n taskId: task.id,\n pluginId: this.pluginId,\n scope: task.scope,\n settings: task.settings,\n taskState:\n this.localWorkersById.get(task.id)?.taskState() ??\n globalState.get(task.id) ??\n null,\n workerState:\n this.localWorkersById.get(task.id)?.workerState() ??\n this.globalWorkersById.get(task.id)?.workerState() ??\n null,\n });\n }\n\n res.json({ tasks });\n });\n\n router.post(\n '/.backstage/scheduler/v1/tasks/:id/trigger',\n async (req, res) => {\n const { id } = req.params;\n await this.triggerTask(id);\n res.status(200).end();\n },\n );\n\n router.post(\n '/.backstage/scheduler/v1/tasks/:id/cancel',\n async (req, res) => {\n const { id } = req.params;\n await this.cancelTask(id);\n res.status(200).end();\n },\n );\n\n return router;\n }\n\n private instrumentedFunction(\n task: SchedulerServiceTaskInvocationDefinition,\n scope: string,\n ): SchedulerServiceTaskFunction {\n return async abort => {\n const labels: Record<string, string> = {\n taskId: task.id,\n scope,\n };\n this.counter.add(1, { ...labels, result: 'started' });\n this.lastStarted.record(Date.now() / 1000, { taskId: task.id });\n\n const startTime = process.hrtime();\n\n try {\n await tracer.startActiveSpan(`task ${task.id}`, async span => {\n try {\n span.setAttributes(labels);\n await task.fn(abort);\n } catch (error) {\n if (error instanceof Error) {\n span.recordException(error);\n }\n throw error;\n } finally {\n span.end();\n }\n });\n labels.result = 'completed';\n } catch (ex) {\n labels.result = 'failed';\n throw ex;\n } finally {\n const delta = process.hrtime(startTime);\n const endTime = delta[0] + delta[1] / 1e9;\n this.counter.add(1, labels);\n this.duration.record(endTime, labels);\n this.lastCompleted.record(Date.now() / 1000, labels);\n }\n };\n }\n}\n\nexport function parseDuration(\n frequency: SchedulerServiceTaskScheduleDefinition['frequency'],\n): string {\n if (typeof frequency === 'object' && 'cron' in frequency) {\n return frequency.cron;\n }\n if (typeof frequency === 'object' && 'trigger' in frequency) {\n return frequency.trigger;\n }\n\n const parsed = Duration.isDuration(frequency)\n ? frequency\n : Duration.fromObject(frequency);\n\n if (!parsed.isValid) {\n throw new Error(\n `Invalid duration, ${parsed.invalidReason}: ${parsed.invalidExplanation}`,\n );\n }\n\n return parsed.toISO()!;\n}\n"],"names":["trace","TRACER_ID","TaskWorker","validateId","delegateAbortController","TaskStatePoller","LocalTaskWorker","Router","Duration"],"mappings":";;;;;;;;;;;;;;AA2CA,MAAM,MAAA,GAASA,SAAA,CAAM,SAAA,CAAUC,cAAS,CAAA;AAKjC,MAAM,uBAAA,CAAoD;AAAA,EAC9C,gBAAA,uBAAuB,GAAA,EAA6B;AAAA,EACpD,iBAAA,uBAAwB,GAAA,EAAwB;AAAA,EAChD,oBAAsD,EAAC;AAAA,EACvD,iBAAA;AAAA,EAEA,OAAA;AAAA,EACA,QAAA;AAAA,EACA,WAAA;AAAA,EACA,aAAA;AAAA,EAEA,QAAA;AAAA,EACA,eAAA;AAAA,EACA,MAAA;AAAA,EACT,MAAA;AAAA,EAER,WAAA,CACE,QAAA,EACA,eAAA,EACA,MAAA,EACA,SACA,aAAA,EACA;AACA,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,eAAA,GAAkB,eAAA;AACvB,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA,CAAQ,aAAA,CAAc,+BAAA,EAAiC;AAAA,MACpE,WAAA,EAAa;AAAA,KACd,CAAA;AACD,IAAA,IAAA,CAAK,WAAW,OAAA,CAAQ,eAAA;AAAA,MACtB,kCAAA;AAAA,MACA;AAAA,QACE,WAAA,EAAa,iCAAA;AAAA,QACb,IAAA,EAAM;AAAA;AACR,KACF;AACA,IAAA,IAAA,CAAK,WAAA,GAAc,OAAA,CAAQ,WAAA,CAAY,iCAAA,EAAmC;AAAA,MACxE,WAAA,EAAa,wDAAA;AAAA,MACb,IAAA,EAAM;AAAA,KACP,CAAA;AACD,IAAA,IAAA,CAAK,gBAAgB,OAAA,CAAQ,WAAA;AAAA,MAC3B,mCAAA;AAAA,MACA;AAAA,QACE,WAAA,EAAa,0DAAA;AAAA,QACb,IAAA,EAAM;AAAA;AACR,KACF;AACA,IAAA,IAAA,CAAK,iBAAA,GAAoB,IAAI,OAAA,CAAQ,CAAA,iBAAA,KAAqB;AACxD,MAAA,aAAA,CAAc,eAAA,CAAgB,MAAM,iBAAA,CAAkB,IAAI,CAAC,CAAA;AAAA,IAC7D,CAAC,CAAA;AAAA,EACH;AAAA,EAEA,MAAM,YAAY,EAAA,EAA2B;AAC3C,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,EAAE,CAAA;AAC9C,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,SAAA,CAAU,OAAA,EAAQ;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,eAAA,EAAgB;AACxC,IAAA,MAAMC,qBAAA,CAAW,OAAA,CAAQ,IAAA,EAAM,EAAE,CAAA;AAAA,EACnC;AAAA,EAEA,MAAM,WAAW,EAAA,EAA2B;AAC1C,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,EAAE,CAAA;AAC9C,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,SAAA,CAAU,MAAA,EAAO;AACjB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,eAAA,EAAgB;AACxC,IAAA,MAAMA,qBAAA,CAAW,MAAA,CAAO,IAAA,EAAM,EAAE,CAAA;AAAA,EAClC;AAAA,EAEA,MAAM,aACJ,IAAA,EAEe;AACf,IAAAC,eAAA,CAAW,KAAK,EAAE,CAAA;AAClB,IAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,IAAS,QAAA;AAE5B,IAAA,MAAM,QAAA,GAA2B;AAAA,MAC/B,OAAA,EAAS,CAAA;AAAA,MACT,OAAA,EAAS,aAAA,CAAc,IAAA,CAAK,SAAS,CAAA;AAAA,MACrC,oBAAA,EACE,IAAA,CAAK,YAAA,IAAgB,aAAA,CAAc,KAAK,YAAY,CAAA;AAAA,MACtD,oBAAA,EAAsB,aAAA,CAAc,IAAA,CAAK,OAAO;AAAA,KAClD;AAIA,IAAA,MAAM,eAAA,GAAkBC,4BAAA,CAAwB,IAAA,CAAK,MAAM,CAAA;AAC3D,IAAA,IAAA,CAAK,iBAAA,CAAkB,IAAA,CAAK,MAAM,eAAA,CAAgB,OAAO,CAAA;AAEzD,IAAA,IAAI,UAAU,QAAA,EAAU;AACtB,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,eAAA,EAAgB;AAExC,MAAA,IAAI,CAAC,KAAK,MAAA,EAAQ;AAChB,QAAA,IAAA,CAAK,MAAA,GAAS,IAAIC,+BAAA,CAAgB;AAAA,UAChC,IAAA;AAAA,UACA,QAAQ,IAAA,CAAK,MAAA,CAAO,MAAM,EAAE,IAAA,EAAM,mBAAmB;AAAA,SACtD,CAAA;AAAA,MACH;AAEA,MAAA,MAAM,SAAS,IAAIH,qBAAA;AAAA,QACjB,IAAA,CAAK,EAAA;AAAA,QACL,IAAA,CAAK,oBAAA,CAAqB,IAAA,EAAM,KAAK,CAAA;AAAA,QACrC,IAAA;AAAA,QACA,KAAK,MAAA,CAAO,KAAA,CAAM,EAAE,IAAA,EAAM,IAAA,CAAK,IAAI,CAAA;AAAA,QACnC,IAAA,CAAK;AAAA,OACP;AACA,MAAA,MAAM,OAAO,KAAA,CAAM,QAAA,EAAU,EAAE,MAAA,EAAQ,eAAA,CAAgB,QAAQ,CAAA;AAC/D,MAAA,IAAA,CAAK,iBAAA,CAAkB,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,MAAM,CAAA;AAAA,IAC5C,CAAA,MAAO;AACL,MAAA,MAAM,SAAS,IAAII,+BAAA;AAAA,QACjB,IAAA,CAAK,EAAA;AAAA,QACL,IAAA,CAAK,oBAAA,CAAqB,IAAA,EAAM,KAAK,CAAA;AAAA,QACrC,KAAK,MAAA,CAAO,KAAA,CAAM,EAAE,IAAA,EAAM,IAAA,CAAK,IAAI;AAAA,OACrC;AACA,MAAA,MAAA,CAAO,MAAM,QAAA,EAAU,EAAE,MAAA,EAAQ,eAAA,CAAgB,QAAQ,CAAA;AACzD,MAAA,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,IAAA,CAAK,EAAA,EAAI,MAAM,CAAA;AAAA,IAC3C;AAEA,IAAA,IAAA,CAAK,kBAAkB,IAAA,CAAK;AAAA,MAC1B,IAAI,IAAA,CAAK,EAAA;AAAA,MACT,KAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AAAA,EAEA,0BACE,QAAA,EAC4B;AAC5B,IAAA,OAAO;AAAA,MACL,GAAA,EAAK,OAAM,IAAA,KAAQ;AACjB,QAAA,MAAM,KAAK,YAAA,CAAa,EAAE,GAAG,IAAA,EAAM,GAAG,UAAU,CAAA;AAAA,MAClD;AAAA,KACF;AAAA,EACF;AAAA,EAEA,MAAM,iBAAA,GAA+D;AACnE,IAAA,OAAO,IAAA,CAAK,iBAAA;AAAA,EACd;AAAA,EAEA,SAAA,GAA4B;AAC1B,IAAA,MAAM,SAASC,uBAAA,EAAO;AAEtB,IAAA,MAAA,CAAO,GAAA,CAAI,gCAAA,EAAkC,OAAO,CAAA,EAAG,GAAA,KAAQ;AAC7D,MAAA,MAAM,WAAA,GAAc,MAAML,qBAAA,CAAW,UAAA;AAAA,QACnC,MAAM,KAAK,eAAA;AAAgB,OAC7B;AAEA,MAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,EAA4B;AAC9C,MAAA,KAAA,MAAW,IAAA,IAAQ,KAAK,iBAAA,EAAmB;AACzC,QAAA,KAAA,CAAM,IAAA,CAAK;AAAA,UACT,QAAQ,IAAA,CAAK,EAAA;AAAA,UACb,UAAU,IAAA,CAAK,QAAA;AAAA,UACf,OAAO,IAAA,CAAK,KAAA;AAAA,UACZ,UAAU,IAAA,CAAK,QAAA;AAAA,UACf,SAAA,EACE,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA,EAAG,SAAA,EAAU,IAC9C,WAAA,CAAY,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA,IACvB,IAAA;AAAA,UACF,aACE,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA,EAAG,WAAA,EAAY,IAChD,IAAA,CAAK,kBAAkB,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA,EAAG,aAAY,IACjD;AAAA,SACH,CAAA;AAAA,MACH;AAEA,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,KAAA,EAAO,CAAA;AAAA,IACpB,CAAC,CAAA;AAED,IAAA,MAAA,CAAO,IAAA;AAAA,MACL,4CAAA;AAAA,MACA,OAAO,KAAK,GAAA,KAAQ;AAClB,QAAA,MAAM,EAAE,EAAA,EAAG,GAAI,GAAA,CAAI,MAAA;AACnB,QAAA,MAAM,IAAA,CAAK,YAAY,EAAE,CAAA;AACzB,QAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,GAAA,EAAI;AAAA,MACtB;AAAA,KACF;AAEA,IAAA,MAAA,CAAO,IAAA;AAAA,MACL,2CAAA;AAAA,MACA,OAAO,KAAK,GAAA,KAAQ;AAClB,QAAA,MAAM,EAAE,EAAA,EAAG,GAAI,GAAA,CAAI,MAAA;AACnB,QAAA,MAAM,IAAA,CAAK,WAAW,EAAE,CAAA;AACxB,QAAA,GAAA,CAAI,MAAA,CAAO,GAAG,CAAA,CAAE,GAAA,EAAI;AAAA,MACtB;AAAA,KACF;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEQ,oBAAA,CACN,MACA,KAAA,EAC8B;AAC9B,IAAA,OAAO,OAAM,KAAA,KAAS;AACpB,MAAA,MAAM,MAAA,GAAiC;AAAA,QACrC,QAAQ,IAAA,CAAK,EAAA;AAAA,QACb;AAAA,OACF;AACA,MAAA,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAA,EAAG,EAAE,GAAG,MAAA,EAAQ,MAAA,EAAQ,WAAW,CAAA;AACpD,MAAA,IAAA,CAAK,WAAA,CAAY,MAAA,CAAO,IAAA,CAAK,GAAA,EAAI,GAAI,KAAM,EAAE,MAAA,EAAQ,IAAA,CAAK,EAAA,EAAI,CAAA;AAE9D,MAAA,MAAM,SAAA,GAAY,QAAQ,MAAA,EAAO;AAEjC,MAAA,IAAI;AACF,QAAA,MAAM,OAAO,eAAA,CAAgB,CAAA,KAAA,EAAQ,KAAK,EAAE,CAAA,CAAA,EAAI,OAAM,IAAA,KAAQ;AAC5D,UAAA,IAAI;AACF,YAAA,IAAA,CAAK,cAAc,MAAM,CAAA;AACzB,YAAA,MAAM,IAAA,CAAK,GAAG,KAAK,CAAA;AAAA,UACrB,SAAS,KAAA,EAAO;AACd,YAAA,IAAI,iBAAiB,KAAA,EAAO;AAC1B,cAAA,IAAA,CAAK,gBAAgB,KAAK,CAAA;AAAA,YAC5B;AACA,YAAA,MAAM,KAAA;AAAA,UACR,CAAA,SAAE;AACA,YAAA,IAAA,CAAK,GAAA,EAAI;AAAA,UACX;AAAA,QACF,CAAC,CAAA;AACD,QAAA,MAAA,CAAO,MAAA,GAAS,WAAA;AAAA,MAClB,SAAS,EAAA,EAAI;AACX,QAAA,MAAA,CAAO,MAAA,GAAS,QAAA;AAChB,QAAA,MAAM,EAAA;AAAA,MACR,CAAA,SAAE;AACA,QAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,MAAA,CAAO,SAAS,CAAA;AACtC,QAAA,MAAM,UAAU,KAAA,CAAM,CAAC,CAAA,GAAI,KAAA,CAAM,CAAC,CAAA,GAAI,GAAA;AACtC,QAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAG,MAAM,CAAA;AAC1B,QAAA,IAAA,CAAK,QAAA,CAAS,MAAA,CAAO,OAAA,EAAS,MAAM,CAAA;AACpC,QAAA,IAAA,CAAK,cAAc,MAAA,CAAO,IAAA,CAAK,GAAA,EAAI,GAAI,KAAM,MAAM,CAAA;AAAA,MACrD;AAAA,IACF,CAAA;AAAA,EACF;AACF;AAEO,SAAS,cACd,SAAA,EACQ;AACR,EAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,MAAA,IAAU,SAAA,EAAW;AACxD,IAAA,OAAO,SAAA,CAAU,IAAA;AAAA,EACnB;AACA,EAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,SAAA,IAAa,SAAA,EAAW;AAC3D,IAAA,OAAO,SAAA,CAAU,OAAA;AAAA,EACnB;AAEA,EAAA,MAAM,MAAA,GAASM,eAAS,UAAA,CAAW,SAAS,IACxC,SAAA,GACAA,cAAA,CAAS,WAAW,SAAS,CAAA;AAEjC,EAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,kBAAA,EAAqB,MAAA,CAAO,aAAa,CAAA,EAAA,EAAK,OAAO,kBAAkB,CAAA;AAAA,KACzE;AAAA,EACF;AAEA,EAAA,OAAO,OAAO,KAAA,EAAM;AACtB;;;;;"}
|
|
1
|
+
{"version":3,"file":"PluginTaskSchedulerImpl.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n LoggerService,\n RootLifecycleService,\n SchedulerService,\n SchedulerServiceTaskDescriptor,\n SchedulerServiceTaskFunction,\n SchedulerServiceTaskInvocationDefinition,\n SchedulerServiceTaskRunner,\n SchedulerServiceTaskScheduleDefinition,\n} from '@backstage/backend-plugin-api';\nimport { trace } from '@opentelemetry/api';\nimport {\n MetricsService,\n MetricsServiceCounter,\n MetricsServiceGauge,\n MetricsServiceHistogram,\n} from '@backstage/backend-plugin-api/alpha';\nimport { Knex } from 'knex';\nimport { Duration } from 'luxon';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { LocalTaskWorker } from './LocalTaskWorker';\nimport { TaskStatePoller } from './TaskStatePoller';\nimport { TaskWorker } from './TaskWorker';\nimport { TaskSettingsV2, TaskApiTasksResponse } from './types';\nimport { delegateAbortController, TRACER_ID, validateId } from './util';\n\nconst tracer = trace.getTracer(TRACER_ID);\n\n/**\n * Implements the actual task management.\n */\nexport class PluginTaskSchedulerImpl implements SchedulerService {\n private readonly localWorkersById = new Map<string, LocalTaskWorker>();\n private readonly globalWorkersById = new Map<string, TaskWorker>();\n private readonly allScheduledTasks: SchedulerServiceTaskDescriptor[] = [];\n private readonly shutdownInitiated: Promise<boolean>;\n\n private readonly counter: MetricsServiceCounter;\n private readonly duration: MetricsServiceHistogram;\n private readonly lastStarted: MetricsServiceGauge;\n private readonly lastCompleted: MetricsServiceGauge;\n\n private readonly pluginId: string;\n private readonly databaseFactory: () => Promise<Knex>;\n private readonly logger: LoggerService;\n private poller?: TaskStatePoller;\n\n constructor(\n pluginId: string,\n databaseFactory: () => Promise<Knex>,\n logger: LoggerService,\n metrics: MetricsService,\n rootLifecycle: RootLifecycleService,\n ) {\n this.pluginId = pluginId;\n this.databaseFactory = databaseFactory;\n this.logger = logger;\n this.counter = metrics.createCounter('backend_tasks.task.runs.count', {\n description: 'Total number of times a task has been run',\n });\n this.duration = metrics.createHistogram(\n 'backend_tasks.task.runs.duration',\n {\n description: 'Histogram of task run durations',\n unit: 'seconds',\n },\n );\n this.lastStarted = metrics.createGauge('backend_tasks.task.runs.started', {\n description: 'Epoch timestamp seconds when the task was last started',\n unit: 'seconds',\n });\n this.lastCompleted = metrics.createGauge(\n 'backend_tasks.task.runs.completed',\n {\n description: 'Epoch timestamp seconds when the task was last completed',\n unit: 'seconds',\n },\n );\n this.shutdownInitiated = new Promise(shutdownInitiated => {\n rootLifecycle.addShutdownHook(() => shutdownInitiated(true));\n });\n }\n\n async triggerTask(id: string): Promise<void> {\n const localTask = this.localWorkersById.get(id);\n if (localTask) {\n localTask.trigger();\n return;\n }\n\n const knex = await this.databaseFactory();\n await TaskWorker.trigger(knex, id);\n }\n\n async cancelTask(id: string): Promise<void> {\n const localTask = this.localWorkersById.get(id);\n if (localTask) {\n localTask.cancel();\n return;\n }\n\n const knex = await this.databaseFactory();\n await TaskWorker.cancel(knex, id);\n }\n\n async scheduleTask(\n task: SchedulerServiceTaskScheduleDefinition &\n SchedulerServiceTaskInvocationDefinition,\n ): Promise<void> {\n validateId(task.id);\n const scope = task.scope ?? 'global';\n\n const settings: TaskSettingsV2 = {\n version: 2,\n cadence: parseDuration(task.frequency),\n initialDelayDuration:\n task.initialDelay && parseDuration(task.initialDelay),\n timeoutAfterDuration: parseDuration(task.timeout),\n };\n\n // Delegated abort controller that will abort either when the provided\n // controller aborts, or when a root lifecycle shutdown happens\n const abortController = delegateAbortController(task.signal);\n this.shutdownInitiated.then(() => abortController.abort());\n\n if (scope === 'global') {\n const knex = await this.databaseFactory();\n\n if (!this.poller) {\n this.poller = new TaskStatePoller({\n knex,\n logger: this.logger.child({ type: 'taskStatePoller' }),\n });\n }\n\n const worker = new TaskWorker(\n task.id,\n this.instrumentedFunction(task, scope),\n knex,\n this.logger.child({ task: task.id }),\n this.poller,\n );\n await worker.start(settings, { signal: abortController.signal });\n this.globalWorkersById.set(task.id, worker);\n } else {\n const worker = new LocalTaskWorker(\n task.id,\n this.instrumentedFunction(task, scope),\n this.logger.child({ task: task.id }),\n );\n worker.start(settings, { signal: abortController.signal });\n this.localWorkersById.set(task.id, worker);\n }\n\n this.allScheduledTasks.push({\n id: task.id,\n scope: scope,\n settings: settings,\n });\n }\n\n createScheduledTaskRunner(\n schedule: SchedulerServiceTaskScheduleDefinition,\n ): SchedulerServiceTaskRunner {\n return {\n run: async task => {\n await this.scheduleTask({ ...task, ...schedule });\n },\n };\n }\n\n async getScheduledTasks(): Promise<SchedulerServiceTaskDescriptor[]> {\n return this.allScheduledTasks;\n }\n\n getRouter(): express.Router {\n const router = Router();\n\n router.get('/.backstage/scheduler/v1/tasks', async (_, res) => {\n const globalState = await TaskWorker.taskStates(\n await this.databaseFactory(),\n );\n\n const tasks = new Array<TaskApiTasksResponse>();\n for (const task of this.allScheduledTasks) {\n tasks.push({\n taskId: task.id,\n pluginId: this.pluginId,\n scope: task.scope,\n settings: task.settings,\n taskState:\n this.localWorkersById.get(task.id)?.taskState() ??\n globalState.get(task.id) ??\n null,\n workerState:\n this.localWorkersById.get(task.id)?.workerState() ??\n this.globalWorkersById.get(task.id)?.workerState() ??\n null,\n });\n }\n\n res.json({ tasks });\n });\n\n router.post(\n '/.backstage/scheduler/v1/tasks/:id/trigger',\n async (req, res) => {\n const { id } = req.params;\n await this.triggerTask(id);\n res.status(200).end();\n },\n );\n\n router.post(\n '/.backstage/scheduler/v1/tasks/:id/cancel',\n async (req, res) => {\n const { id } = req.params;\n await this.cancelTask(id);\n res.status(200).end();\n },\n );\n\n return router;\n }\n\n private instrumentedFunction(\n task: SchedulerServiceTaskInvocationDefinition,\n scope: string,\n ): SchedulerServiceTaskFunction {\n return async abort => {\n const labels: Record<string, string> = {\n taskId: task.id,\n scope,\n };\n this.counter.add(1, { ...labels, result: 'started' });\n this.lastStarted.record(Date.now() / 1000, { taskId: task.id });\n\n const startTime = process.hrtime();\n\n try {\n await tracer.startActiveSpan(`task ${task.id}`, async span => {\n try {\n span.setAttributes(labels);\n await task.fn(abort);\n } catch (error) {\n if (error instanceof Error) {\n span.recordException(error);\n }\n throw error;\n } finally {\n span.end();\n }\n });\n labels.result = 'completed';\n } catch (ex) {\n labels.result = 'failed';\n throw ex;\n } finally {\n const delta = process.hrtime(startTime);\n const endTime = delta[0] + delta[1] / 1e9;\n this.counter.add(1, labels);\n this.duration.record(endTime, labels);\n this.lastCompleted.record(Date.now() / 1000, labels);\n }\n };\n }\n}\n\nexport function parseDuration(\n frequency: SchedulerServiceTaskScheduleDefinition['frequency'],\n): string {\n if (typeof frequency === 'object' && 'cron' in frequency) {\n return frequency.cron;\n }\n if (typeof frequency === 'object' && 'trigger' in frequency) {\n return frequency.trigger;\n }\n\n const parsed = Duration.isDuration(frequency)\n ? frequency\n : Duration.fromObject(frequency);\n\n if (!parsed.isValid) {\n throw new Error(\n `Invalid duration, ${parsed.invalidReason}: ${parsed.invalidExplanation}`,\n );\n }\n\n return parsed.toISO()!;\n}\n"],"names":["trace","TRACER_ID","TaskWorker","validateId","delegateAbortController","TaskStatePoller","LocalTaskWorker","Router","Duration"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluginTaskSchedulerJanitor.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { Knex } from 'knex';\nimport { Duration } from 'luxon';\nimport { DB_TASKS_TABLE, DbTasksRow } from '../database/tables';\nimport { serializeError, sleep } from './util';\n\n/**\n * Makes sure to auto-expire and clean up things that time out or for other\n * reasons should not be left lingering.\n */\nexport class PluginTaskSchedulerJanitor {\n private readonly knex: Knex;\n private readonly waitBetweenRuns: Duration;\n private readonly logger: LoggerService;\n\n constructor(options: {\n knex: Knex;\n waitBetweenRuns: Duration;\n logger: LoggerService;\n }) {\n this.knex = options.knex;\n this.waitBetweenRuns = options.waitBetweenRuns;\n this.logger = options.logger;\n }\n\n async start(abortSignal?: AbortSignal) {\n while (!abortSignal?.aborted) {\n try {\n await this.runOnce();\n } catch (e) {\n this.logger.warn(`Error while performing janitorial tasks, ${e}`);\n }\n\n await sleep(this.waitBetweenRuns, abortSignal);\n }\n }\n\n private async runOnce() {\n const dbNull = this.knex.raw('null');\n const configClient = this.knex.client.config.client;\n\n let tasks: Array<{ id: string }>;\n if (configClient.includes('sqlite3') || configClient.includes('mysql')) {\n tasks = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .select('id')\n .where('current_run_expires_at', '<', this.knex.fn.now());\n await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .whereIn(\n 'id',\n tasks.map(t => t.id),\n )\n .update({\n current_run_ticket: dbNull,\n current_run_started_at: dbNull,\n current_run_expires_at: dbNull,\n last_run_ended_at: this.knex.fn.now(),\n last_run_error_json: serializeError(new Error('Task timed out')),\n });\n } else {\n tasks = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('current_run_expires_at', '<', this.knex.fn.now())\n .update({\n current_run_ticket: dbNull,\n current_run_started_at: dbNull,\n current_run_expires_at: dbNull,\n last_run_ended_at: this.knex.fn.now(),\n last_run_error_json: serializeError(new Error('Task timed out')),\n })\n .returning(['id']);\n }\n\n // In rare cases, knex drivers may ignore \"returning\", and return the number\n // of rows changed instead\n if (typeof tasks === 'number') {\n if (tasks > 0) {\n this.logger.warn(`${tasks} tasks timed out and were lost`);\n }\n } else {\n for (const { id } of tasks) {\n this.logger.warn(`Task timed out and was lost: ${id}`);\n }\n }\n }\n}\n"],"names":["sleep","DB_TASKS_TABLE","serializeError"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"PluginTaskSchedulerJanitor.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/PluginTaskSchedulerJanitor.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { Knex } from 'knex';\nimport { Duration } from 'luxon';\nimport { DB_TASKS_TABLE, DbTasksRow } from '../database/tables';\nimport { serializeError, sleep } from './util';\n\n/**\n * Makes sure to auto-expire and clean up things that time out or for other\n * reasons should not be left lingering.\n */\nexport class PluginTaskSchedulerJanitor {\n private readonly knex: Knex;\n private readonly waitBetweenRuns: Duration;\n private readonly logger: LoggerService;\n\n constructor(options: {\n knex: Knex;\n waitBetweenRuns: Duration;\n logger: LoggerService;\n }) {\n this.knex = options.knex;\n this.waitBetweenRuns = options.waitBetweenRuns;\n this.logger = options.logger;\n }\n\n async start(abortSignal?: AbortSignal) {\n while (!abortSignal?.aborted) {\n try {\n await this.runOnce();\n } catch (e) {\n this.logger.warn(`Error while performing janitorial tasks, ${e}`);\n }\n\n await sleep(this.waitBetweenRuns, abortSignal);\n }\n }\n\n private async runOnce() {\n const dbNull = this.knex.raw('null');\n const configClient = this.knex.client.config.client;\n\n let tasks: Array<{ id: string }>;\n if (configClient.includes('sqlite3') || configClient.includes('mysql')) {\n tasks = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .select('id')\n .where('current_run_expires_at', '<', this.knex.fn.now());\n await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .whereIn(\n 'id',\n tasks.map(t => t.id),\n )\n .update({\n current_run_ticket: dbNull,\n current_run_started_at: dbNull,\n current_run_expires_at: dbNull,\n last_run_ended_at: this.knex.fn.now(),\n last_run_error_json: serializeError(new Error('Task timed out')),\n });\n } else {\n tasks = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('current_run_expires_at', '<', this.knex.fn.now())\n .update({\n current_run_ticket: dbNull,\n current_run_started_at: dbNull,\n current_run_expires_at: dbNull,\n last_run_ended_at: this.knex.fn.now(),\n last_run_error_json: serializeError(new Error('Task timed out')),\n })\n .returning(['id']);\n }\n\n // In rare cases, knex drivers may ignore \"returning\", and return the number\n // of rows changed instead\n if (typeof tasks === 'number') {\n if (tasks > 0) {\n this.logger.warn(`${tasks} tasks timed out and were lost`);\n }\n } else {\n for (const { id } of tasks) {\n this.logger.warn(`Task timed out and was lost: ${id}`);\n }\n }\n }\n}\n"],"names":["sleep","DB_TASKS_TABLE","serializeError"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskStatePoller.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/TaskStatePoller.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { createDeferred, DeferredPromise } from '@backstage/types';\nimport { Knex } from 'knex';\nimport { Duration } from 'luxon';\nimport { DB_TASKS_TABLE, DbTasksRow } from '../database/tables';\nimport { TaskSettingsV2, taskSettingsV2Schema } from './types';\n\ntype TaskPollResult =\n | { result: 'abort' }\n | { result: 'ready'; settings: TaskSettingsV2 };\n\ninterface PendingWaiter {\n taskId: string;\n deferred: DeferredPromise<TaskPollResult>;\n pollIntervalMs: number;\n signal: AbortSignal;\n abortHandler: () => void;\n}\n\nconst MIN_POLL_INTERVAL_MS = 100;\n\n/**\n * Batches readiness checks for all waiting tasks of a plugin.\n */\nexport class TaskStatePoller {\n readonly #knex: Knex;\n readonly #logger: LoggerService;\n readonly #waiters = new Map<string, Set<PendingWaiter>>();\n #pollTimer: ReturnType<typeof setTimeout> | undefined;\n #pollTimerDueAt: number | undefined;\n #nextPollAllowedAt: number | undefined;\n #pollCycleRunning = false;\n\n constructor(options: { knex: Knex; logger: LoggerService }) {\n this.#knex = options.knex;\n this.#logger = options.logger;\n }\n\n waitForTask(\n taskId: string,\n options: { signal: AbortSignal; pollInterval: Duration },\n ): Promise<TaskPollResult> {\n if (options.signal.aborted) {\n return Promise.resolve({ result: 'abort' });\n }\n\n const requestedPollIntervalMs = options.pollInterval.as('milliseconds');\n if (\n !Number.isFinite(requestedPollIntervalMs) ||\n requestedPollIntervalMs <= 0\n ) {\n throw new TypeError('pollInterval must be a finite positive duration');\n }\n const pollIntervalMs = Math.max(\n requestedPollIntervalMs,\n MIN_POLL_INTERVAL_MS,\n );\n\n const deferred = createDeferred<TaskPollResult>();\n const waiter: PendingWaiter = {\n taskId,\n deferred,\n pollIntervalMs,\n signal: options.signal,\n abortHandler: () => {\n this.#removeWaiter(waiter);\n deferred.resolve({ result: 'abort' });\n },\n };\n\n let waiters = this.#waiters.get(taskId);\n if (!waiters) {\n waiters = new Set();\n this.#waiters.set(taskId, waiters);\n }\n waiters.add(waiter);\n options.signal.addEventListener('abort', waiter.abortHandler, {\n once: true,\n });\n\n this.#ensurePolling();\n this.#rescheduleFor(waiter);\n return deferred;\n }\n\n #ensurePolling(): void {\n if (this.#pollCycleRunning || this.#pollTimer) {\n return;\n }\n\n const delayMs = (this.#nextPollAllowedAt ?? 0) - Date.now();\n if (delayMs > 0) {\n this.#schedulePoll(delayMs);\n return;\n }\n\n this.#pollCycleRunning = true;\n Promise.resolve().then(() => this.#runPollCycle());\n }\n\n async #runPollCycle(): Promise<void> {\n const cyclePollIntervalMs = this.#nextPollIntervalMs();\n if (!Number.isFinite(cyclePollIntervalMs)) {\n this.#pollCycleRunning = false;\n this.#nextPollAllowedAt = undefined;\n return;\n }\n\n try {\n await this.#poll();\n } catch (error) {\n this.#logger.warn('Task state poll failed', error);\n }\n this.#pollCycleRunning = false;\n\n const currentPollIntervalMs = this.#nextPollIntervalMs();\n const nextPollCooldownMs = Math.min(\n cyclePollIntervalMs,\n currentPollIntervalMs,\n );\n this.#nextPollAllowedAt = Date.now() + nextPollCooldownMs;\n if (this.#waiters.size > 0) {\n this.#schedulePoll(currentPollIntervalMs);\n }\n }\n\n #schedulePoll(delayMs: number): void {\n this.#pollTimerDueAt = Date.now() + delayMs;\n this.#pollTimer = setTimeout(() => {\n this.#pollTimer = undefined;\n this.#pollTimerDueAt = undefined;\n if (this.#waiters.size === 0) {\n return;\n }\n this.#pollCycleRunning = true;\n this.#runPollCycle();\n }, delayMs);\n }\n\n #rescheduleFor(waiter: PendingWaiter): void {\n if (!this.#pollTimer || this.#pollTimerDueAt === undefined) {\n return;\n }\n\n const desiredPollAt = Date.now() + waiter.pollIntervalMs;\n if (desiredPollAt >= this.#pollTimerDueAt) {\n return;\n }\n\n clearTimeout(this.#pollTimer);\n this.#schedulePoll(waiter.pollIntervalMs);\n }\n\n #nextPollIntervalMs(): number {\n let intervalMs = Infinity;\n for (const waiters of this.#waiters.values()) {\n for (const waiter of waiters) {\n intervalMs = Math.min(intervalMs, waiter.pollIntervalMs);\n }\n }\n return intervalMs;\n }\n\n async #poll(): Promise<void> {\n const taskIds = [...this.#waiters.keys()];\n if (taskIds.length === 0) {\n return;\n }\n\n const rows = await this.#knex<DbTasksRow>(DB_TASKS_TABLE)\n .whereIn('id', taskIds)\n .select({\n id: 'id',\n settingsJson: 'settings_json',\n ready: this.#knex.raw(\n `CASE\n WHEN next_run_start_at <= ? AND current_run_ticket IS NULL THEN TRUE\n ELSE FALSE\n END`,\n [this.#knex.fn.now()],\n ),\n });\n\n const foundIds = new Set<string>();\n\n for (const row of rows) {\n foundIds.add(row.id);\n\n if (!row.ready) {\n continue;\n }\n\n try {\n const settings = taskSettingsV2Schema.parse(\n JSON.parse(row.settingsJson),\n );\n this.#resolveAll(row.id, { result: 'ready', settings });\n } catch (error) {\n this.#logger.info(\n `Task \"${row.id}\" is no longer able to parse task settings; aborting and assuming that a newer version of the task has been issued and is being handled by other workers, ${error}`,\n );\n this.#resolveAll(row.id, { result: 'abort' });\n }\n }\n\n for (const taskId of taskIds) {\n if (!foundIds.has(taskId)) {\n this.#logger.info(\n `No longer able to find task \"${taskId}\"; aborting and assuming that it has been unregistered or expired`,\n );\n this.#resolveAll(taskId, { result: 'abort' });\n }\n }\n }\n\n #resolveAll(taskId: string, result: TaskPollResult): void {\n const waiters = this.#waiters.get(taskId);\n if (!waiters) {\n return;\n }\n this.#waiters.delete(taskId);\n\n for (const waiter of waiters) {\n this.#cleanupWaiter(waiter);\n waiter.deferred.resolve(result);\n }\n }\n\n #removeWaiter(waiter: PendingWaiter): void {\n const waiters = this.#waiters.get(waiter.taskId);\n if (!waiters) {\n return;\n }\n waiters.delete(waiter);\n this.#cleanupWaiter(waiter);\n if (waiters.size === 0) {\n this.#waiters.delete(waiter.taskId);\n }\n if (this.#waiters.size === 0 && this.#pollTimer) {\n clearTimeout(this.#pollTimer);\n this.#pollTimer = undefined;\n this.#pollTimerDueAt = undefined;\n this.#nextPollAllowedAt = undefined;\n }\n }\n\n #cleanupWaiter(waiter: PendingWaiter): void {\n waiter.signal.removeEventListener('abort', waiter.abortHandler);\n }\n}\n"],"names":["createDeferred","DB_TASKS_TABLE","taskSettingsV2Schema"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TaskStatePoller.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/TaskStatePoller.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { createDeferred, DeferredPromise } from '@backstage/types';\nimport { Knex } from 'knex';\nimport { Duration } from 'luxon';\nimport { DB_TASKS_TABLE, DbTasksRow } from '../database/tables';\nimport { TaskSettingsV2, taskSettingsV2Schema } from './types';\n\ntype TaskPollResult =\n | { result: 'abort' }\n | { result: 'ready'; settings: TaskSettingsV2 };\n\ninterface PendingWaiter {\n taskId: string;\n deferred: DeferredPromise<TaskPollResult>;\n pollIntervalMs: number;\n signal: AbortSignal;\n abortHandler: () => void;\n}\n\nconst MIN_POLL_INTERVAL_MS = 100;\n\n/**\n * Batches readiness checks for all waiting tasks of a plugin.\n */\nexport class TaskStatePoller {\n readonly #knex: Knex;\n readonly #logger: LoggerService;\n readonly #waiters = new Map<string, Set<PendingWaiter>>();\n #pollTimer: ReturnType<typeof setTimeout> | undefined;\n #pollTimerDueAt: number | undefined;\n #nextPollAllowedAt: number | undefined;\n #pollCycleRunning = false;\n\n constructor(options: { knex: Knex; logger: LoggerService }) {\n this.#knex = options.knex;\n this.#logger = options.logger;\n }\n\n waitForTask(\n taskId: string,\n options: { signal: AbortSignal; pollInterval: Duration },\n ): Promise<TaskPollResult> {\n if (options.signal.aborted) {\n return Promise.resolve({ result: 'abort' });\n }\n\n const requestedPollIntervalMs = options.pollInterval.as('milliseconds');\n if (\n !Number.isFinite(requestedPollIntervalMs) ||\n requestedPollIntervalMs <= 0\n ) {\n throw new TypeError('pollInterval must be a finite positive duration');\n }\n const pollIntervalMs = Math.max(\n requestedPollIntervalMs,\n MIN_POLL_INTERVAL_MS,\n );\n\n const deferred = createDeferred<TaskPollResult>();\n const waiter: PendingWaiter = {\n taskId,\n deferred,\n pollIntervalMs,\n signal: options.signal,\n abortHandler: () => {\n this.#removeWaiter(waiter);\n deferred.resolve({ result: 'abort' });\n },\n };\n\n let waiters = this.#waiters.get(taskId);\n if (!waiters) {\n waiters = new Set();\n this.#waiters.set(taskId, waiters);\n }\n waiters.add(waiter);\n options.signal.addEventListener('abort', waiter.abortHandler, {\n once: true,\n });\n\n this.#ensurePolling();\n this.#rescheduleFor(waiter);\n return deferred;\n }\n\n #ensurePolling(): void {\n if (this.#pollCycleRunning || this.#pollTimer) {\n return;\n }\n\n const delayMs = (this.#nextPollAllowedAt ?? 0) - Date.now();\n if (delayMs > 0) {\n this.#schedulePoll(delayMs);\n return;\n }\n\n this.#pollCycleRunning = true;\n Promise.resolve().then(() => this.#runPollCycle());\n }\n\n async #runPollCycle(): Promise<void> {\n const cyclePollIntervalMs = this.#nextPollIntervalMs();\n if (!Number.isFinite(cyclePollIntervalMs)) {\n this.#pollCycleRunning = false;\n this.#nextPollAllowedAt = undefined;\n return;\n }\n\n try {\n await this.#poll();\n } catch (error) {\n this.#logger.warn('Task state poll failed', error);\n }\n this.#pollCycleRunning = false;\n\n const currentPollIntervalMs = this.#nextPollIntervalMs();\n const nextPollCooldownMs = Math.min(\n cyclePollIntervalMs,\n currentPollIntervalMs,\n );\n this.#nextPollAllowedAt = Date.now() + nextPollCooldownMs;\n if (this.#waiters.size > 0) {\n this.#schedulePoll(currentPollIntervalMs);\n }\n }\n\n #schedulePoll(delayMs: number): void {\n this.#pollTimerDueAt = Date.now() + delayMs;\n this.#pollTimer = setTimeout(() => {\n this.#pollTimer = undefined;\n this.#pollTimerDueAt = undefined;\n if (this.#waiters.size === 0) {\n return;\n }\n this.#pollCycleRunning = true;\n this.#runPollCycle();\n }, delayMs);\n }\n\n #rescheduleFor(waiter: PendingWaiter): void {\n if (!this.#pollTimer || this.#pollTimerDueAt === undefined) {\n return;\n }\n\n const desiredPollAt = Date.now() + waiter.pollIntervalMs;\n if (desiredPollAt >= this.#pollTimerDueAt) {\n return;\n }\n\n clearTimeout(this.#pollTimer);\n this.#schedulePoll(waiter.pollIntervalMs);\n }\n\n #nextPollIntervalMs(): number {\n let intervalMs = Infinity;\n for (const waiters of this.#waiters.values()) {\n for (const waiter of waiters) {\n intervalMs = Math.min(intervalMs, waiter.pollIntervalMs);\n }\n }\n return intervalMs;\n }\n\n async #poll(): Promise<void> {\n const taskIds = [...this.#waiters.keys()];\n if (taskIds.length === 0) {\n return;\n }\n\n const rows = await this.#knex<DbTasksRow>(DB_TASKS_TABLE)\n .whereIn('id', taskIds)\n .select({\n id: 'id',\n settingsJson: 'settings_json',\n ready: this.#knex.raw(\n `CASE\n WHEN next_run_start_at <= ? AND current_run_ticket IS NULL THEN TRUE\n ELSE FALSE\n END`,\n [this.#knex.fn.now()],\n ),\n });\n\n const foundIds = new Set<string>();\n\n for (const row of rows) {\n foundIds.add(row.id);\n\n if (!row.ready) {\n continue;\n }\n\n try {\n const settings = taskSettingsV2Schema.parse(\n JSON.parse(row.settingsJson),\n );\n this.#resolveAll(row.id, { result: 'ready', settings });\n } catch (error) {\n this.#logger.info(\n `Task \"${row.id}\" is no longer able to parse task settings; aborting and assuming that a newer version of the task has been issued and is being handled by other workers, ${error}`,\n );\n this.#resolveAll(row.id, { result: 'abort' });\n }\n }\n\n for (const taskId of taskIds) {\n if (!foundIds.has(taskId)) {\n this.#logger.info(\n `No longer able to find task \"${taskId}\"; aborting and assuming that it has been unregistered or expired`,\n );\n this.#resolveAll(taskId, { result: 'abort' });\n }\n }\n }\n\n #resolveAll(taskId: string, result: TaskPollResult): void {\n const waiters = this.#waiters.get(taskId);\n if (!waiters) {\n return;\n }\n this.#waiters.delete(taskId);\n\n for (const waiter of waiters) {\n this.#cleanupWaiter(waiter);\n waiter.deferred.resolve(result);\n }\n }\n\n #removeWaiter(waiter: PendingWaiter): void {\n const waiters = this.#waiters.get(waiter.taskId);\n if (!waiters) {\n return;\n }\n waiters.delete(waiter);\n this.#cleanupWaiter(waiter);\n if (waiters.size === 0) {\n this.#waiters.delete(waiter.taskId);\n }\n if (this.#waiters.size === 0 && this.#pollTimer) {\n clearTimeout(this.#pollTimer);\n this.#pollTimer = undefined;\n this.#pollTimerDueAt = undefined;\n this.#nextPollAllowedAt = undefined;\n }\n }\n\n #cleanupWaiter(waiter: PendingWaiter): void {\n waiter.signal.removeEventListener('abort', waiter.abortHandler);\n }\n}\n"],"names":["createDeferred","DB_TASKS_TABLE","taskSettingsV2Schema"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskWorker.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/TaskWorker.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { CronTime } from 'cron';\nimport { Knex } from 'knex';\nimport { DateTime, Duration } from 'luxon';\nimport { randomUUID as uuid } from 'node:crypto';\nimport { DB_TASKS_TABLE, DbTasksRow } from '../database/tables';\nimport {\n TaskSettingsV2,\n taskSettingsV2Schema,\n TaskApiTasksResponse,\n} from './types';\nimport {\n delegateAbortController,\n nowPlus,\n sleep,\n dbTime,\n serializeError,\n} from './util';\nimport { SchedulerServiceTaskFunction } from '@backstage/backend-plugin-api';\nimport { TaskStatePoller } from './TaskStatePoller';\n\nconst DEFAULT_WORK_CHECK_FREQUENCY = Duration.fromObject({ seconds: 5 });\n\n/**\n * Implements tasks that run across worker hosts, with collaborative locking.\n *\n * @private\n */\nexport class TaskWorker {\n #workerState: TaskApiTasksResponse['workerState'] = {\n status: 'idle',\n };\n private readonly taskId: string;\n private readonly fn: SchedulerServiceTaskFunction;\n private readonly knex: Knex;\n private readonly logger: LoggerService;\n private readonly poller: TaskStatePoller;\n private readonly workCheckFrequency: Duration;\n\n constructor(\n taskId: string,\n fn: SchedulerServiceTaskFunction,\n knex: Knex,\n logger: LoggerService,\n poller: TaskStatePoller,\n workCheckFrequency: Duration = DEFAULT_WORK_CHECK_FREQUENCY,\n ) {\n this.taskId = taskId;\n this.fn = fn;\n this.knex = knex;\n this.logger = logger;\n this.poller = poller;\n this.workCheckFrequency = workCheckFrequency;\n }\n\n async start(settings: TaskSettingsV2, options: { signal: AbortSignal }) {\n try {\n await this.persistTask(settings);\n } catch (e) {\n throw new Error(`Failed to persist task, ${e}`);\n }\n\n this.logger.info(\n `Registered scheduled task: ${this.taskId}, ${JSON.stringify(settings)}`,\n );\n\n let workCheckFrequency = this.workCheckFrequency;\n const isDuration = settings.cadence.startsWith('P');\n if (isDuration) {\n const cadence = Duration.fromISO(settings.cadence);\n if (cadence.as('milliseconds') > 0 && cadence < workCheckFrequency) {\n workCheckFrequency = cadence;\n }\n }\n\n (async () => {\n let attemptNum = 1;\n for (;;) {\n try {\n await this.performInitialWait(settings, options.signal);\n\n while (!options.signal.aborted) {\n const runResult = await this.runOnce(\n options.signal,\n workCheckFrequency,\n );\n if (runResult.result === 'abort') {\n break;\n }\n }\n\n this.logger.info(`Task worker finished: ${this.taskId}`);\n attemptNum = 0;\n break;\n } catch (e) {\n if (options.signal.aborted) {\n break;\n }\n attemptNum += 1;\n this.logger.warn(\n `Task worker failed unexpectedly, attempt number ${attemptNum}, ${e}`,\n );\n await sleep(Duration.fromObject({ seconds: 1 }), options.signal);\n }\n }\n })();\n }\n\n /**\n * Does the once-at-startup initial wait, if configured.\n */\n private async performInitialWait(\n settings: TaskSettingsV2,\n signal: AbortSignal,\n ): Promise<void> {\n if (settings.initialDelayDuration) {\n this.#workerState = {\n status: 'initial-wait',\n };\n await sleep(Duration.fromISO(settings.initialDelayDuration), signal);\n }\n this.#workerState = {\n status: 'idle',\n };\n }\n\n static async trigger(knex: Knex, taskId: string): Promise<void> {\n // check if task exists\n const rows = await knex<DbTasksRow>(DB_TASKS_TABLE)\n .select(knex.raw(1))\n .where('id', '=', taskId);\n if (rows.length !== 1) {\n throw new NotFoundError(`Task ${taskId} does not exist`);\n }\n\n const updatedRows = await knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', taskId)\n .whereNull('current_run_ticket')\n .update({\n next_run_start_at: knex.fn.now(),\n });\n if (updatedRows < 1) {\n throw new ConflictError(`Task ${taskId} is currently running`);\n }\n }\n\n static async cancel(knex: Knex, taskId: string): Promise<void> {\n const [row] = await knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', taskId)\n .select('settings_json', 'current_run_ticket');\n if (!row) {\n throw new NotFoundError(`Task ${taskId} does not exist`);\n }\n if (!row.current_run_ticket) {\n throw new ConflictError(`Task ${taskId} is not running`);\n }\n\n const settings = taskSettingsV2Schema.parse(JSON.parse(row.settings_json));\n const nextRun = TaskWorker.computeNextRunStartAt(knex, settings);\n\n const updatedRows = await knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', taskId)\n .where('current_run_ticket', '=', row.current_run_ticket)\n .update({\n next_run_start_at: nextRun,\n current_run_ticket: knex.raw('null'),\n current_run_started_at: knex.raw('null'),\n current_run_expires_at: knex.raw('null'),\n last_run_ended_at: knex.fn.now(),\n last_run_error_json: serializeError(new Error('Task was cancelled')),\n });\n if (updatedRows < 1) {\n throw new ConflictError(`Task ${taskId} is not running`);\n }\n }\n\n static async taskStates(\n knex: Knex,\n ): Promise<Map<string, TaskApiTasksResponse['taskState']>> {\n const rows = await knex<DbTasksRow>(DB_TASKS_TABLE);\n return new Map(\n rows.map(row => {\n const startedAt = row.current_run_started_at\n ? dbTime(row.current_run_started_at).toISO()!\n : undefined;\n const timesOutAt = row.current_run_expires_at\n ? dbTime(row.current_run_expires_at).toISO()!\n : undefined;\n const startsAt = row.next_run_start_at\n ? dbTime(row.next_run_start_at).toISO()!\n : undefined;\n const lastRunEndedAt = row.last_run_ended_at\n ? dbTime(row.last_run_ended_at).toISO()!\n : undefined;\n const lastRunError = row.last_run_error_json || undefined;\n\n return [\n row.id,\n startedAt\n ? {\n status: 'running',\n startedAt,\n timesOutAt,\n lastRunEndedAt,\n lastRunError,\n }\n : {\n status: 'idle',\n startsAt,\n lastRunEndedAt,\n lastRunError,\n },\n ];\n }),\n );\n }\n\n workerState(): TaskApiTasksResponse['workerState'] {\n return this.#workerState;\n }\n\n /**\n * Makes a single attempt at running the task to completion, if ready.\n * Waits for the shared poller to signal readiness instead of querying\n * the database directly.\n */\n private async runOnce(\n signal: AbortSignal,\n workCheckFrequency: Duration,\n ): Promise<\n | { result: 'abort' }\n | { result: 'claim-lost' }\n | { result: 'failed' }\n | { result: 'completed' }\n > {\n const findResult = await this.poller.waitForTask(this.taskId, {\n signal,\n pollInterval: workCheckFrequency,\n });\n if (findResult.result === 'abort') {\n return findResult;\n }\n return this.claimAndRun(findResult.settings, signal);\n }\n\n private async claimAndRun(\n taskSettings: TaskSettingsV2,\n signal: AbortSignal,\n ): Promise<\n { result: 'claim-lost' } | { result: 'failed' } | { result: 'completed' }\n > {\n const ticket = uuid();\n\n const claimed = await this.tryClaimTask(ticket, taskSettings);\n if (!claimed) {\n return { result: 'claim-lost' };\n }\n\n // Abort the task execution either if the worker is stopped, or if the\n // task timeout is hit, or if the task ticket was lost (e.g. due to\n // cancellation from another host)\n const taskAbortController = delegateAbortController(signal);\n const timeoutHandle = setTimeout(() => {\n taskAbortController.abort();\n }, Duration.fromISO(taskSettings.timeoutAfterDuration).as('milliseconds'));\n let livenessHandle: ReturnType<typeof setTimeout> | undefined;\n const scheduleLivenessCheck = () => {\n livenessHandle = setTimeout(async () => {\n await this.checkLiveness(ticket, taskAbortController);\n if (!taskAbortController.signal.aborted) {\n scheduleLivenessCheck();\n }\n }, this.workCheckFrequency.as('milliseconds'));\n };\n scheduleLivenessCheck();\n\n try {\n this.#workerState = {\n status: 'running',\n };\n await this.fn(taskAbortController.signal);\n taskAbortController.abort(); // releases resources\n } catch (e) {\n this.logger.error(e);\n await this.tryReleaseTask(ticket, taskSettings, e);\n return { result: 'failed' };\n } finally {\n this.#workerState = {\n status: 'idle',\n };\n clearTimeout(timeoutHandle);\n clearTimeout(livenessHandle);\n }\n\n await this.tryReleaseTask(ticket, taskSettings);\n return { result: 'completed' };\n }\n\n /**\n * Perform the initial store of the task info\n */\n async persistTask(settings: TaskSettingsV2) {\n // Perform an initial parse to ensure that we will definitely be able to\n // read it back again.\n taskSettingsV2Schema.parse(settings);\n\n const isManual = settings?.cadence === 'manual';\n const isDuration = settings?.cadence.startsWith('P');\n const isCron = !isManual && !isDuration;\n\n let startAt: Knex.Raw | undefined;\n let nextStartAt: Knex.Raw | undefined;\n if (settings.initialDelayDuration) {\n startAt = nowPlus(\n Duration.fromISO(settings.initialDelayDuration),\n this.knex,\n );\n }\n\n if (isCron) {\n const time = new CronTime(settings.cadence)\n .sendAt()\n .minus({ seconds: 1 }) // immediately, if \"* * * * * *\"\n .toUTC();\n // We make a conversion here to make typescript happy, because the luxon versions of the cron library and here may not be the same\n const timeConverted = DateTime.fromJSDate(time.toJSDate());\n\n nextStartAt = TaskWorker.nextRunAtRaw(this.knex, timeConverted);\n startAt ||= nextStartAt;\n } else if (isManual) {\n nextStartAt = this.knex.raw('null');\n startAt ||= nextStartAt;\n } else {\n startAt ||= this.knex.fn.now();\n nextStartAt = nowPlus(Duration.fromISO(settings.cadence), this.knex);\n }\n\n this.logger.debug(`task: ${this.taskId} configured to run at: ${startAt}`);\n\n // It's OK if the task already exists; if it does, just replace its\n // settings with the new value and start the loop as usual.\n const settingsJson = JSON.stringify(settings);\n await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .insert({\n id: this.taskId,\n settings_json: settingsJson,\n next_run_start_at: startAt,\n })\n .onConflict('id')\n .merge(\n this.knex.client.config.client.includes('mysql')\n ? {\n settings_json: settingsJson,\n next_run_start_at: this.knex.raw(\n `CASE WHEN ?? IS NULL OR ?? < ?? THEN ?? ELSE ?? END`,\n [\n 'next_run_start_at',\n nextStartAt,\n 'next_run_start_at',\n nextStartAt,\n 'next_run_start_at',\n ],\n ),\n }\n : {\n settings_json: this.knex.ref('excluded.settings_json'),\n next_run_start_at: this.knex.raw(\n `CASE WHEN ?? IS NULL OR ?? < ?? THEN ?? ELSE ?? END`,\n [\n `${DB_TASKS_TABLE}.next_run_start_at`,\n nextStartAt,\n `${DB_TASKS_TABLE}.next_run_start_at`,\n nextStartAt,\n `${DB_TASKS_TABLE}.next_run_start_at`,\n ],\n ),\n },\n );\n }\n\n /**\n * Checks whether the current task ticket is still valid in the database.\n * If the ticket has been cleared (e.g. by cancellation or janitor cleanup),\n * aborts the task execution.\n */\n private async checkLiveness(\n ticket: string,\n taskAbortController: AbortController,\n ): Promise<void> {\n try {\n const [row] = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', this.taskId)\n .select('current_run_ticket');\n\n if (!row || row.current_run_ticket !== ticket) {\n this.logger.info(\n `Task ticket for \"${this.taskId}\" is no longer valid; aborting execution`,\n );\n taskAbortController.abort();\n }\n } catch (e) {\n this.logger.warn(\n `Failed to check liveness for task \"${this.taskId}\", ${e}`,\n );\n }\n }\n\n /**\n * Attempts to claim a task that's ready for execution, on this worker's\n * behalf. We should not attempt to perform the work unless the claim really\n * goes through.\n *\n * @param ticket - A globally unique string that changes for each invocation\n * @param settings - The settings of the task to claim\n * @returns True if it was successfully claimed\n */\n async tryClaimTask(\n ticket: string,\n settings: TaskSettingsV2,\n ): Promise<boolean> {\n const startedAt = this.knex.fn.now();\n const expiresAt = settings.timeoutAfterDuration\n ? nowPlus(Duration.fromISO(settings.timeoutAfterDuration), this.knex)\n : this.knex.raw('null');\n\n const rows = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', this.taskId)\n .whereNull('current_run_ticket')\n .update({\n current_run_ticket: ticket,\n current_run_started_at: startedAt,\n current_run_expires_at: expiresAt,\n });\n\n return rows === 1;\n }\n\n private static computeNextRunStartAt(\n knex: Knex,\n settings: TaskSettingsV2,\n ): Knex.Raw {\n const isManual = settings?.cadence === 'manual';\n const isDuration = settings?.cadence.startsWith('P');\n const isCron = !isManual && !isDuration;\n\n if (isCron) {\n const time = new CronTime(settings.cadence).sendAt().toUTC();\n const timeConverted = DateTime.fromJSDate(time.toJSDate());\n return TaskWorker.nextRunAtRaw(knex, timeConverted);\n }\n\n if (isManual) {\n return knex.raw('null');\n }\n\n const dt = Duration.fromISO(settings.cadence).as('seconds');\n\n if (knex.client.config.client.includes('sqlite3')) {\n return knex.raw(`max(datetime(next_run_start_at, ?), datetime('now'))`, [\n `+${dt} seconds`,\n ]);\n }\n\n if (knex.client.config.client.includes('mysql')) {\n return knex.raw(\n `greatest(next_run_start_at + interval ${dt} second, now())`,\n );\n }\n\n return knex.raw(\n `greatest(next_run_start_at + interval '${dt} seconds', now())`,\n );\n }\n\n async tryReleaseTask(\n ticket: string,\n settings: TaskSettingsV2,\n error?: Error,\n ): Promise<boolean> {\n const nextRun = TaskWorker.computeNextRunStartAt(this.knex, settings);\n\n const rows = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', this.taskId)\n .where('current_run_ticket', '=', ticket)\n .update({\n next_run_start_at: nextRun,\n current_run_ticket: this.knex.raw('null'),\n current_run_started_at: this.knex.raw('null'),\n current_run_expires_at: this.knex.raw('null'),\n last_run_ended_at: this.knex.fn.now(),\n last_run_error_json: error\n ? serializeError(error)\n : this.knex.raw('null'),\n });\n\n return rows === 1;\n }\n\n private static nextRunAtRaw(knex: Knex, time: DateTime): Knex.Raw {\n if (knex.client.config.client.includes('sqlite3')) {\n return knex.raw('datetime(?)', [time.toISO()]);\n }\n if (knex.client.config.client.includes('mysql')) {\n return knex.raw(`?`, [time.toSQL({ includeOffset: false })]);\n }\n return knex.raw(`?`, [time.toISO()]);\n }\n}\n"],"names":["Duration","sleep","DB_TASKS_TABLE","NotFoundError","ConflictError","taskSettingsV2Schema","serializeError","dbTime","uuid","delegateAbortController","nowPlus","CronTime","DateTime"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TaskWorker.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/TaskWorker.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LoggerService } from '@backstage/backend-plugin-api';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { CronTime } from 'cron';\nimport { Knex } from 'knex';\nimport { DateTime, Duration } from 'luxon';\nimport { randomUUID as uuid } from 'node:crypto';\nimport { DB_TASKS_TABLE, DbTasksRow } from '../database/tables';\nimport {\n TaskSettingsV2,\n taskSettingsV2Schema,\n TaskApiTasksResponse,\n} from './types';\nimport {\n delegateAbortController,\n nowPlus,\n sleep,\n dbTime,\n serializeError,\n} from './util';\nimport { SchedulerServiceTaskFunction } from '@backstage/backend-plugin-api';\nimport { TaskStatePoller } from './TaskStatePoller';\n\nconst DEFAULT_WORK_CHECK_FREQUENCY = Duration.fromObject({ seconds: 5 });\n\n/**\n * Implements tasks that run across worker hosts, with collaborative locking.\n *\n * @private\n */\nexport class TaskWorker {\n #workerState: TaskApiTasksResponse['workerState'] = {\n status: 'idle',\n };\n private readonly taskId: string;\n private readonly fn: SchedulerServiceTaskFunction;\n private readonly knex: Knex;\n private readonly logger: LoggerService;\n private readonly poller: TaskStatePoller;\n private readonly workCheckFrequency: Duration;\n\n constructor(\n taskId: string,\n fn: SchedulerServiceTaskFunction,\n knex: Knex,\n logger: LoggerService,\n poller: TaskStatePoller,\n workCheckFrequency: Duration = DEFAULT_WORK_CHECK_FREQUENCY,\n ) {\n this.taskId = taskId;\n this.fn = fn;\n this.knex = knex;\n this.logger = logger;\n this.poller = poller;\n this.workCheckFrequency = workCheckFrequency;\n }\n\n async start(settings: TaskSettingsV2, options: { signal: AbortSignal }) {\n try {\n await this.persistTask(settings);\n } catch (e) {\n throw new Error(`Failed to persist task, ${e}`);\n }\n\n this.logger.info(\n `Registered scheduled task: ${this.taskId}, ${JSON.stringify(settings)}`,\n );\n\n let workCheckFrequency = this.workCheckFrequency;\n const isDuration = settings.cadence.startsWith('P');\n if (isDuration) {\n const cadence = Duration.fromISO(settings.cadence);\n if (cadence.as('milliseconds') > 0 && cadence < workCheckFrequency) {\n workCheckFrequency = cadence;\n }\n }\n\n (async () => {\n let attemptNum = 1;\n for (;;) {\n try {\n await this.performInitialWait(settings, options.signal);\n\n while (!options.signal.aborted) {\n const runResult = await this.runOnce(\n options.signal,\n workCheckFrequency,\n );\n if (runResult.result === 'abort') {\n break;\n }\n }\n\n this.logger.info(`Task worker finished: ${this.taskId}`);\n attemptNum = 0;\n break;\n } catch (e) {\n if (options.signal.aborted) {\n break;\n }\n attemptNum += 1;\n this.logger.warn(\n `Task worker failed unexpectedly, attempt number ${attemptNum}, ${e}`,\n );\n await sleep(Duration.fromObject({ seconds: 1 }), options.signal);\n }\n }\n })();\n }\n\n /**\n * Does the once-at-startup initial wait, if configured.\n */\n private async performInitialWait(\n settings: TaskSettingsV2,\n signal: AbortSignal,\n ): Promise<void> {\n if (settings.initialDelayDuration) {\n this.#workerState = {\n status: 'initial-wait',\n };\n await sleep(Duration.fromISO(settings.initialDelayDuration), signal);\n }\n this.#workerState = {\n status: 'idle',\n };\n }\n\n static async trigger(knex: Knex, taskId: string): Promise<void> {\n // check if task exists\n const rows = await knex<DbTasksRow>(DB_TASKS_TABLE)\n .select(knex.raw(1))\n .where('id', '=', taskId);\n if (rows.length !== 1) {\n throw new NotFoundError(`Task ${taskId} does not exist`);\n }\n\n const updatedRows = await knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', taskId)\n .whereNull('current_run_ticket')\n .update({\n next_run_start_at: knex.fn.now(),\n });\n if (updatedRows < 1) {\n throw new ConflictError(`Task ${taskId} is currently running`);\n }\n }\n\n static async cancel(knex: Knex, taskId: string): Promise<void> {\n const [row] = await knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', taskId)\n .select('settings_json', 'current_run_ticket');\n if (!row) {\n throw new NotFoundError(`Task ${taskId} does not exist`);\n }\n if (!row.current_run_ticket) {\n throw new ConflictError(`Task ${taskId} is not running`);\n }\n\n const settings = taskSettingsV2Schema.parse(JSON.parse(row.settings_json));\n const nextRun = TaskWorker.computeNextRunStartAt(knex, settings);\n\n const updatedRows = await knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', taskId)\n .where('current_run_ticket', '=', row.current_run_ticket)\n .update({\n next_run_start_at: nextRun,\n current_run_ticket: knex.raw('null'),\n current_run_started_at: knex.raw('null'),\n current_run_expires_at: knex.raw('null'),\n last_run_ended_at: knex.fn.now(),\n last_run_error_json: serializeError(new Error('Task was cancelled')),\n });\n if (updatedRows < 1) {\n throw new ConflictError(`Task ${taskId} is not running`);\n }\n }\n\n static async taskStates(\n knex: Knex,\n ): Promise<Map<string, TaskApiTasksResponse['taskState']>> {\n const rows = await knex<DbTasksRow>(DB_TASKS_TABLE);\n return new Map(\n rows.map(row => {\n const startedAt = row.current_run_started_at\n ? dbTime(row.current_run_started_at).toISO()!\n : undefined;\n const timesOutAt = row.current_run_expires_at\n ? dbTime(row.current_run_expires_at).toISO()!\n : undefined;\n const startsAt = row.next_run_start_at\n ? dbTime(row.next_run_start_at).toISO()!\n : undefined;\n const lastRunEndedAt = row.last_run_ended_at\n ? dbTime(row.last_run_ended_at).toISO()!\n : undefined;\n const lastRunError = row.last_run_error_json || undefined;\n\n return [\n row.id,\n startedAt\n ? {\n status: 'running',\n startedAt,\n timesOutAt,\n lastRunEndedAt,\n lastRunError,\n }\n : {\n status: 'idle',\n startsAt,\n lastRunEndedAt,\n lastRunError,\n },\n ];\n }),\n );\n }\n\n workerState(): TaskApiTasksResponse['workerState'] {\n return this.#workerState;\n }\n\n /**\n * Makes a single attempt at running the task to completion, if ready.\n * Waits for the shared poller to signal readiness instead of querying\n * the database directly.\n */\n private async runOnce(\n signal: AbortSignal,\n workCheckFrequency: Duration,\n ): Promise<\n | { result: 'abort' }\n | { result: 'claim-lost' }\n | { result: 'failed' }\n | { result: 'completed' }\n > {\n const findResult = await this.poller.waitForTask(this.taskId, {\n signal,\n pollInterval: workCheckFrequency,\n });\n if (findResult.result === 'abort') {\n return findResult;\n }\n return this.claimAndRun(findResult.settings, signal);\n }\n\n private async claimAndRun(\n taskSettings: TaskSettingsV2,\n signal: AbortSignal,\n ): Promise<\n { result: 'claim-lost' } | { result: 'failed' } | { result: 'completed' }\n > {\n const ticket = uuid();\n\n const claimed = await this.tryClaimTask(ticket, taskSettings);\n if (!claimed) {\n return { result: 'claim-lost' };\n }\n\n // Abort the task execution either if the worker is stopped, or if the\n // task timeout is hit, or if the task ticket was lost (e.g. due to\n // cancellation from another host)\n const taskAbortController = delegateAbortController(signal);\n const timeoutHandle = setTimeout(() => {\n taskAbortController.abort();\n }, Duration.fromISO(taskSettings.timeoutAfterDuration).as('milliseconds'));\n let livenessHandle: ReturnType<typeof setTimeout> | undefined;\n const scheduleLivenessCheck = () => {\n livenessHandle = setTimeout(async () => {\n await this.checkLiveness(ticket, taskAbortController);\n if (!taskAbortController.signal.aborted) {\n scheduleLivenessCheck();\n }\n }, this.workCheckFrequency.as('milliseconds'));\n };\n scheduleLivenessCheck();\n\n try {\n this.#workerState = {\n status: 'running',\n };\n await this.fn(taskAbortController.signal);\n taskAbortController.abort(); // releases resources\n } catch (e) {\n this.logger.error(e);\n await this.tryReleaseTask(ticket, taskSettings, e);\n return { result: 'failed' };\n } finally {\n this.#workerState = {\n status: 'idle',\n };\n clearTimeout(timeoutHandle);\n clearTimeout(livenessHandle);\n }\n\n await this.tryReleaseTask(ticket, taskSettings);\n return { result: 'completed' };\n }\n\n /**\n * Perform the initial store of the task info\n */\n async persistTask(settings: TaskSettingsV2) {\n // Perform an initial parse to ensure that we will definitely be able to\n // read it back again.\n taskSettingsV2Schema.parse(settings);\n\n const isManual = settings?.cadence === 'manual';\n const isDuration = settings?.cadence.startsWith('P');\n const isCron = !isManual && !isDuration;\n\n let startAt: Knex.Raw | undefined;\n let nextStartAt: Knex.Raw | undefined;\n if (settings.initialDelayDuration) {\n startAt = nowPlus(\n Duration.fromISO(settings.initialDelayDuration),\n this.knex,\n );\n }\n\n if (isCron) {\n const time = new CronTime(settings.cadence)\n .sendAt()\n .minus({ seconds: 1 }) // immediately, if \"* * * * * *\"\n .toUTC();\n // We make a conversion here to make typescript happy, because the luxon versions of the cron library and here may not be the same\n const timeConverted = DateTime.fromJSDate(time.toJSDate());\n\n nextStartAt = TaskWorker.nextRunAtRaw(this.knex, timeConverted);\n startAt ||= nextStartAt;\n } else if (isManual) {\n nextStartAt = this.knex.raw('null');\n startAt ||= nextStartAt;\n } else {\n startAt ||= this.knex.fn.now();\n nextStartAt = nowPlus(Duration.fromISO(settings.cadence), this.knex);\n }\n\n this.logger.debug(`task: ${this.taskId} configured to run at: ${startAt}`);\n\n // It's OK if the task already exists; if it does, just replace its\n // settings with the new value and start the loop as usual.\n const settingsJson = JSON.stringify(settings);\n await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .insert({\n id: this.taskId,\n settings_json: settingsJson,\n next_run_start_at: startAt,\n })\n .onConflict('id')\n .merge(\n this.knex.client.config.client.includes('mysql')\n ? {\n settings_json: settingsJson,\n next_run_start_at: this.knex.raw(\n `CASE WHEN ?? IS NULL OR ?? < ?? THEN ?? ELSE ?? END`,\n [\n 'next_run_start_at',\n nextStartAt,\n 'next_run_start_at',\n nextStartAt,\n 'next_run_start_at',\n ],\n ),\n }\n : {\n settings_json: this.knex.ref('excluded.settings_json'),\n next_run_start_at: this.knex.raw(\n `CASE WHEN ?? IS NULL OR ?? < ?? THEN ?? ELSE ?? END`,\n [\n `${DB_TASKS_TABLE}.next_run_start_at`,\n nextStartAt,\n `${DB_TASKS_TABLE}.next_run_start_at`,\n nextStartAt,\n `${DB_TASKS_TABLE}.next_run_start_at`,\n ],\n ),\n },\n );\n }\n\n /**\n * Checks whether the current task ticket is still valid in the database.\n * If the ticket has been cleared (e.g. by cancellation or janitor cleanup),\n * aborts the task execution.\n */\n private async checkLiveness(\n ticket: string,\n taskAbortController: AbortController,\n ): Promise<void> {\n try {\n const [row] = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', this.taskId)\n .select('current_run_ticket');\n\n if (!row || row.current_run_ticket !== ticket) {\n this.logger.info(\n `Task ticket for \"${this.taskId}\" is no longer valid; aborting execution`,\n );\n taskAbortController.abort();\n }\n } catch (e) {\n this.logger.warn(\n `Failed to check liveness for task \"${this.taskId}\", ${e}`,\n );\n }\n }\n\n /**\n * Attempts to claim a task that's ready for execution, on this worker's\n * behalf. We should not attempt to perform the work unless the claim really\n * goes through.\n *\n * @param ticket - A globally unique string that changes for each invocation\n * @param settings - The settings of the task to claim\n * @returns True if it was successfully claimed\n */\n async tryClaimTask(\n ticket: string,\n settings: TaskSettingsV2,\n ): Promise<boolean> {\n const startedAt = this.knex.fn.now();\n const expiresAt = settings.timeoutAfterDuration\n ? nowPlus(Duration.fromISO(settings.timeoutAfterDuration), this.knex)\n : this.knex.raw('null');\n\n const rows = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', this.taskId)\n .whereNull('current_run_ticket')\n .update({\n current_run_ticket: ticket,\n current_run_started_at: startedAt,\n current_run_expires_at: expiresAt,\n });\n\n return rows === 1;\n }\n\n private static computeNextRunStartAt(\n knex: Knex,\n settings: TaskSettingsV2,\n ): Knex.Raw {\n const isManual = settings?.cadence === 'manual';\n const isDuration = settings?.cadence.startsWith('P');\n const isCron = !isManual && !isDuration;\n\n if (isCron) {\n const time = new CronTime(settings.cadence).sendAt().toUTC();\n const timeConverted = DateTime.fromJSDate(time.toJSDate());\n return TaskWorker.nextRunAtRaw(knex, timeConverted);\n }\n\n if (isManual) {\n return knex.raw('null');\n }\n\n const dt = Duration.fromISO(settings.cadence).as('seconds');\n\n if (knex.client.config.client.includes('sqlite3')) {\n return knex.raw(`max(datetime(next_run_start_at, ?), datetime('now'))`, [\n `+${dt} seconds`,\n ]);\n }\n\n if (knex.client.config.client.includes('mysql')) {\n return knex.raw(\n `greatest(next_run_start_at + interval ${dt} second, now())`,\n );\n }\n\n return knex.raw(\n `greatest(next_run_start_at + interval '${dt} seconds', now())`,\n );\n }\n\n async tryReleaseTask(\n ticket: string,\n settings: TaskSettingsV2,\n error?: Error,\n ): Promise<boolean> {\n const nextRun = TaskWorker.computeNextRunStartAt(this.knex, settings);\n\n const rows = await this.knex<DbTasksRow>(DB_TASKS_TABLE)\n .where('id', '=', this.taskId)\n .where('current_run_ticket', '=', ticket)\n .update({\n next_run_start_at: nextRun,\n current_run_ticket: this.knex.raw('null'),\n current_run_started_at: this.knex.raw('null'),\n current_run_expires_at: this.knex.raw('null'),\n last_run_ended_at: this.knex.fn.now(),\n last_run_error_json: error\n ? serializeError(error)\n : this.knex.raw('null'),\n });\n\n return rows === 1;\n }\n\n private static nextRunAtRaw(knex: Knex, time: DateTime): Knex.Raw {\n if (knex.client.config.client.includes('sqlite3')) {\n return knex.raw('datetime(?)', [time.toISO()]);\n }\n if (knex.client.config.client.includes('mysql')) {\n return knex.raw(`?`, [time.toSQL({ includeOffset: false })]);\n }\n return knex.raw(`?`, [time.toISO()]);\n }\n}\n"],"names":["Duration","sleep","DB_TASKS_TABLE","NotFoundError","ConflictError","taskSettingsV2Schema","serializeError","dbTime","uuid","delegateAbortController","nowPlus","CronTime","DateTime"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/types.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JsonObject } from '@backstage/types';\nimport { CronTime } from 'cron';\nimport { Duration } from 'luxon';\nimport { z } from 'zod/v4';\n\nfunction isValidOptionalDurationString(d: string | undefined): boolean {\n try {\n return !d || Duration.fromISO(d).isValid;\n } catch {\n return false;\n }\n}\n\nfunction isValidCronFormat(c: string | undefined): boolean {\n try {\n if (!c) {\n return false;\n }\n // parse cron format to ensure it's a valid format.\n // eslint-disable-next-line no-new\n new CronTime(c);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValidTrigger(t: string): boolean {\n return t === 'manual';\n}\n\nexport const taskSettingsV2Schema = z.object({\n version: z.literal(2),\n cadence: z\n .string()\n .refine(isValidCronFormat, { message: 'Invalid cron' })\n .or(\n z.string().refine(isValidTrigger, {\n message: \"Invalid trigger, expecting 'manual'\",\n }),\n )\n .or(\n z.string().refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n ),\n timeoutAfterDuration: z.string().refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n initialDelayDuration: z\n .string()\n .optional()\n .refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n});\n\n/**\n * The properties that control a scheduled task (version 2).\n */\nexport type TaskSettingsV2 = z.infer<typeof taskSettingsV2Schema>;\n\n/**\n * The shape of a task definition as returned by the service's REST API.\n */\nexport interface TaskApiTasksResponse {\n taskId: string;\n pluginId: string;\n scope: 'global' | 'local';\n settings: { version: number } & JsonObject;\n taskState:\n | {\n status: 'running';\n startedAt: string;\n timesOutAt?: string;\n lastRunError?: string;\n lastRunEndedAt?: string;\n }\n | {\n status: 'idle';\n startsAt?: string;\n lastRunError?: string;\n lastRunEndedAt?: string;\n }\n | null;\n workerState:\n | {\n status: 'initial-wait';\n }\n | {\n status: 'idle';\n }\n | {\n status: 'running';\n }\n | null;\n}\n"],"names":["Duration","CronTime","z"],"mappings":";;;;;;AAqBA,SAAS,8BAA8B,CAAA,EAAgC;AACrE,EAAA,IAAI;AACF,IAAA,OAAO,CAAC,CAAA,IAAKA,cAAA,CAAS,OAAA,CAAQ,CAAC,CAAA,CAAE,OAAA;AAAA,EACnC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,SAAS,kBAAkB,CAAA,EAAgC;AACzD,EAAA,IAAI;AACF,IAAA,IAAI,CAAC,CAAA,EAAG;AACN,MAAA,OAAO,KAAA;AAAA,IACT;AAGA,IAAA,IAAIC,cAAS,CAAC,CAAA;AACd,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,SAAS,eAAe,CAAA,EAAoB;AAC1C,EAAA,OAAO,CAAA,KAAM,QAAA;AACf;AAEO,MAAM,oBAAA,GAAuBC,KAAE,MAAA,CAAO;AAAA,EAC3C,OAAA,EAASA,IAAA,CAAE,OAAA,CAAQ,CAAC,CAAA;AAAA,EACpB,OAAA,EAASA,IAAA,CACN,MAAA,EAAO,CACP,MAAA,CAAO,mBAAmB,EAAE,OAAA,EAAS,cAAA,EAAgB,CAAA,CACrD,EAAA;AAAA,IACCA,IAAA,CAAE,MAAA,EAAO,CAAE,MAAA,CAAO,cAAA,EAAgB;AAAA,MAChC,OAAA,EAAS;AAAA,KACV;AAAA,GACH,CACC,EAAA;AAAA,IACCA,IAAA,CAAE,MAAA,EAAO,CAAE,MAAA,CAAO,6BAAA,EAA+B;AAAA,MAC/C,OAAA,EAAS;AAAA,KACV;AAAA,GACH;AAAA,EACF,oBAAA,EAAsBA,IAAA,CAAE,MAAA,EAAO,CAAE,OAAO,6BAAA,EAA+B;AAAA,IACrE,OAAA,EAAS;AAAA,GACV,CAAA;AAAA,EACD,sBAAsBA,IAAA,CACnB,MAAA,GACA,QAAA,EAAS,CACT,OAAO,6BAAA,EAA+B;AAAA,IACrC,OAAA,EAAS;AAAA,GACV;AACL,CAAC
|
|
1
|
+
{"version":3,"file":"types.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/types.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JsonObject } from '@backstage/types';\nimport { CronTime } from 'cron';\nimport { Duration } from 'luxon';\nimport { z } from 'zod/v4';\n\nfunction isValidOptionalDurationString(d: string | undefined): boolean {\n try {\n return !d || Duration.fromISO(d).isValid;\n } catch {\n return false;\n }\n}\n\nfunction isValidCronFormat(c: string | undefined): boolean {\n try {\n if (!c) {\n return false;\n }\n // parse cron format to ensure it's a valid format.\n // eslint-disable-next-line no-new\n new CronTime(c);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isValidTrigger(t: string): boolean {\n return t === 'manual';\n}\n\nexport const taskSettingsV2Schema = z.object({\n version: z.literal(2),\n cadence: z\n .string()\n .refine(isValidCronFormat, { message: 'Invalid cron' })\n .or(\n z.string().refine(isValidTrigger, {\n message: \"Invalid trigger, expecting 'manual'\",\n }),\n )\n .or(\n z.string().refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n ),\n timeoutAfterDuration: z.string().refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n initialDelayDuration: z\n .string()\n .optional()\n .refine(isValidOptionalDurationString, {\n message: 'Invalid duration, expecting ISO Period',\n }),\n});\n\n/**\n * The properties that control a scheduled task (version 2).\n */\nexport type TaskSettingsV2 = z.infer<typeof taskSettingsV2Schema>;\n\n/**\n * The shape of a task definition as returned by the service's REST API.\n */\nexport interface TaskApiTasksResponse {\n taskId: string;\n pluginId: string;\n scope: 'global' | 'local';\n settings: { version: number } & JsonObject;\n taskState:\n | {\n status: 'running';\n startedAt: string;\n timesOutAt?: string;\n lastRunError?: string;\n lastRunEndedAt?: string;\n }\n | {\n status: 'idle';\n startsAt?: string;\n lastRunError?: string;\n lastRunEndedAt?: string;\n }\n | null;\n workerState:\n | {\n status: 'initial-wait';\n }\n | {\n status: 'idle';\n }\n | {\n status: 'running';\n }\n | null;\n}\n"],"names":["Duration","CronTime","z"],"mappings":";;;;;;AAqBA,SAAS,8BAA8B,CAAA,EAAgC;AACrE,EAAA,IAAI;AACF,IAAA,OAAO,CAAC,CAAA,IAAKA,cAAA,CAAS,OAAA,CAAQ,CAAC,CAAA,CAAE,OAAA;AAAA,EACnC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,SAAS,kBAAkB,CAAA,EAAgC;AACzD,EAAA,IAAI;AACF,IAAA,IAAI,CAAC,CAAA,EAAG;AACN,MAAA,OAAO,KAAA;AAAA,IACT;AAGA,IAAA,IAAIC,cAAS,CAAC,CAAA;AACd,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,SAAS,eAAe,CAAA,EAAoB;AAC1C,EAAA,OAAO,CAAA,KAAM,QAAA;AACf;AAEO,MAAM,oBAAA,GAAuBC,KAAE,MAAA,CAAO;AAAA,EAC3C,OAAA,EAASA,IAAA,CAAE,OAAA,CAAQ,CAAC,CAAA;AAAA,EACpB,OAAA,EAASA,IAAA,CACN,MAAA,EAAO,CACP,MAAA,CAAO,mBAAmB,EAAE,OAAA,EAAS,cAAA,EAAgB,CAAA,CACrD,EAAA;AAAA,IACCA,IAAA,CAAE,MAAA,EAAO,CAAE,MAAA,CAAO,cAAA,EAAgB;AAAA,MAChC,OAAA,EAAS;AAAA,KACV;AAAA,GACH,CACC,EAAA;AAAA,IACCA,IAAA,CAAE,MAAA,EAAO,CAAE,MAAA,CAAO,6BAAA,EAA+B;AAAA,MAC/C,OAAA,EAAS;AAAA,KACV;AAAA,GACH;AAAA,EACF,oBAAA,EAAsBA,IAAA,CAAE,MAAA,EAAO,CAAE,OAAO,6BAAA,EAA+B;AAAA,IACrE,OAAA,EAAS;AAAA,GACV,CAAA;AAAA,EACD,sBAAsBA,IAAA,CACnB,MAAA,GACA,QAAA,EAAS,CACT,OAAO,6BAAA,EAA+B;AAAA,IACrC,OAAA,EAAS;AAAA,GACV;AACL,CAAC;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/util.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n InputError,\n serializeError as internalSerializeError,\n} from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { DateTime, Duration } from 'luxon';\n\nexport const TRACER_ID = 'backstage-service-scheduler';\n\n// Keep the IDs compatible with e.g. Prometheus labels\nexport function validateId(id: string) {\n if (typeof id !== 'string' || !id.trim()) {\n throw new InputError(`${id} is not a valid ID, expected non-empty string`);\n }\n}\n\nexport function dbTime(t: Date | string): DateTime {\n if (typeof t === 'string') {\n return DateTime.fromSQL(t);\n }\n return DateTime.fromJSDate(t);\n}\n\nexport function nowPlus(duration: Duration | undefined, knex: Knex) {\n const seconds = duration?.as('seconds') ?? 0;\n if (!seconds) {\n return knex.fn.now();\n }\n\n if (knex.client.config.client.includes('sqlite3')) {\n return knex.raw(`datetime('now', ?)`, [`${seconds} seconds`]);\n }\n\n if (knex.client.config.client.includes('mysql')) {\n return knex.raw(`now() + interval ${seconds} second`);\n }\n\n return knex.raw(`now() + interval '${seconds} seconds'`);\n}\n\n// Node.js setTimeout uses a 32-bit signed integer internally, so timeouts\n// longer than 2^31-1 ms (~24.8 days) fire immediately. We cap each individual\n// wait at 2^30 ms (~12.4 days) and loop until the full duration has elapsed.\nconst MAX_TIMEOUT_MS = 2 ** 30;\n\n/**\n * Sleep for the given duration, but return sooner if the abort signal\n * triggers.\n *\n * @param duration - The amount of time to sleep, at most\n * @param abortSignal - An optional abort signal that short circuits the wait\n */\nexport async function sleep(\n duration: Duration,\n abortSignal?: AbortSignal,\n): Promise<void> {\n if (abortSignal?.aborted) {\n return;\n }\n\n let remaining = duration.as('milliseconds');\n if (!Number.isFinite(remaining) || remaining <= 0) {\n return;\n }\n\n await new Promise<void>(resolve => {\n let timeoutHandle: NodeJS.Timeout | undefined;\n\n const finish = () => {\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n abortSignal?.removeEventListener('abort', finish);\n resolve();\n };\n\n const tick = () => {\n if (remaining <= 0) {\n finish();\n return;\n }\n const chunk = Math.min(remaining, MAX_TIMEOUT_MS);\n remaining -= chunk;\n timeoutHandle = setTimeout(tick, chunk);\n };\n\n abortSignal?.addEventListener('abort', finish);\n tick();\n });\n}\n\n/**\n * Creates a new AbortController that, in addition to working as a regular\n * standalone controller, also gets aborted if the given parent signal\n * reaches aborted state.\n *\n * @param parent - The \"parent\" signal that can trigger the delegate\n */\nexport function delegateAbortController(parent?: AbortSignal): AbortController {\n const delegate = new AbortController();\n\n if (parent) {\n if (parent.aborted) {\n delegate.abort();\n } else {\n const onParentAborted = () => {\n delegate.abort();\n };\n\n const onChildAborted = () => {\n parent.removeEventListener('abort', onParentAborted);\n };\n\n parent.addEventListener('abort', onParentAborted, { once: true });\n delegate.signal.addEventListener('abort', onChildAborted, { once: true });\n }\n }\n\n return delegate;\n}\n\nexport function serializeError(error: Error): string {\n return JSON.stringify(\n internalSerializeError(error, {\n includeStack: process.env.NODE_ENV === 'development',\n }),\n );\n}\n"],"names":["InputError","DateTime","internalSerializeError"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"util.cjs.js","sources":["../../../../src/entrypoints/scheduler/lib/util.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n InputError,\n serializeError as internalSerializeError,\n} from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { DateTime, Duration } from 'luxon';\n\nexport const TRACER_ID = 'backstage-service-scheduler';\n\n// Keep the IDs compatible with e.g. Prometheus labels\nexport function validateId(id: string) {\n if (typeof id !== 'string' || !id.trim()) {\n throw new InputError(`${id} is not a valid ID, expected non-empty string`);\n }\n}\n\nexport function dbTime(t: Date | string): DateTime {\n if (typeof t === 'string') {\n return DateTime.fromSQL(t);\n }\n return DateTime.fromJSDate(t);\n}\n\nexport function nowPlus(duration: Duration | undefined, knex: Knex) {\n const seconds = duration?.as('seconds') ?? 0;\n if (!seconds) {\n return knex.fn.now();\n }\n\n if (knex.client.config.client.includes('sqlite3')) {\n return knex.raw(`datetime('now', ?)`, [`${seconds} seconds`]);\n }\n\n if (knex.client.config.client.includes('mysql')) {\n return knex.raw(`now() + interval ${seconds} second`);\n }\n\n return knex.raw(`now() + interval '${seconds} seconds'`);\n}\n\n// Node.js setTimeout uses a 32-bit signed integer internally, so timeouts\n// longer than 2^31-1 ms (~24.8 days) fire immediately. We cap each individual\n// wait at 2^30 ms (~12.4 days) and loop until the full duration has elapsed.\nconst MAX_TIMEOUT_MS = 2 ** 30;\n\n/**\n * Sleep for the given duration, but return sooner if the abort signal\n * triggers.\n *\n * @param duration - The amount of time to sleep, at most\n * @param abortSignal - An optional abort signal that short circuits the wait\n */\nexport async function sleep(\n duration: Duration,\n abortSignal?: AbortSignal,\n): Promise<void> {\n if (abortSignal?.aborted) {\n return;\n }\n\n let remaining = duration.as('milliseconds');\n if (!Number.isFinite(remaining) || remaining <= 0) {\n return;\n }\n\n await new Promise<void>(resolve => {\n let timeoutHandle: NodeJS.Timeout | undefined;\n\n const finish = () => {\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n abortSignal?.removeEventListener('abort', finish);\n resolve();\n };\n\n const tick = () => {\n if (remaining <= 0) {\n finish();\n return;\n }\n const chunk = Math.min(remaining, MAX_TIMEOUT_MS);\n remaining -= chunk;\n timeoutHandle = setTimeout(tick, chunk);\n };\n\n abortSignal?.addEventListener('abort', finish);\n tick();\n });\n}\n\n/**\n * Creates a new AbortController that, in addition to working as a regular\n * standalone controller, also gets aborted if the given parent signal\n * reaches aborted state.\n *\n * @param parent - The \"parent\" signal that can trigger the delegate\n */\nexport function delegateAbortController(parent?: AbortSignal): AbortController {\n const delegate = new AbortController();\n\n if (parent) {\n if (parent.aborted) {\n delegate.abort();\n } else {\n const onParentAborted = () => {\n delegate.abort();\n };\n\n const onChildAborted = () => {\n parent.removeEventListener('abort', onParentAborted);\n };\n\n parent.addEventListener('abort', onParentAborted, { once: true });\n delegate.signal.addEventListener('abort', onChildAborted, { once: true });\n }\n }\n\n return delegate;\n}\n\nexport function serializeError(error: Error): string {\n return JSON.stringify(\n internalSerializeError(error, {\n includeStack: process.env.NODE_ENV === 'development',\n }),\n );\n}\n"],"names":["InputError","DateTime","internalSerializeError"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schedulerServiceFactory.cjs.js","sources":["../../../src/entrypoints/scheduler/schedulerServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { metricsServiceRef } from '@backstage/backend-plugin-api/alpha';\nimport { DefaultSchedulerService } from './lib/DefaultSchedulerService';\n\n/**\n * Scheduling of distributed background tasks.\n *\n * See {@link @backstage/code-plugin-api#SchedulerService}\n * and {@link https://backstage.io/docs/backend-system/core-services/scheduler | the service docs}\n * for more information.\n *\n * @public\n */\nexport const schedulerServiceFactory = createServiceFactory({\n service: coreServices.scheduler,\n deps: {\n database: coreServices.database,\n logger: coreServices.logger,\n rootLifecycle: coreServices.rootLifecycle,\n httpRouter: coreServices.httpRouter,\n pluginMetadata: coreServices.pluginMetadata,\n metrics: metricsServiceRef,\n },\n async factory({\n database,\n logger,\n rootLifecycle,\n httpRouter,\n pluginMetadata,\n metrics,\n }) {\n return DefaultSchedulerService.create({\n database,\n logger,\n rootLifecycle,\n httpRouter,\n pluginMetadata,\n metrics,\n });\n },\n});\n"],"names":["createServiceFactory","coreServices","metricsServiceRef","DefaultSchedulerService"],"mappings":";;;;;;AAgCO,MAAM,0BAA0BA,qCAAA,CAAqB;AAAA,EAC1D,SAASC,6BAAA,CAAa,SAAA;AAAA,EACtB,IAAA,EAAM;AAAA,IACJ,UAAUA,6BAAA,CAAa,QAAA;AAAA,IACvB,QAAQA,6BAAA,CAAa,MAAA;AAAA,IACrB,eAAeA,6BAAA,CAAa,aAAA;AAAA,IAC5B,YAAYA,6BAAA,CAAa,UAAA;AAAA,IACzB,gBAAgBA,6BAAA,CAAa,cAAA;AAAA,IAC7B,OAAA,EAASC;AAAA,GACX;AAAA,EACA,MAAM,OAAA,CAAQ;AAAA,IACZ,QAAA;AAAA,IACA,MAAA;AAAA,IACA,aAAA;AAAA,IACA,UAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,GACF,EAAG;AACD,IAAA,OAAOC,gDAAwB,MAAA,CAAO;AAAA,MACpC,QAAA;AAAA,MACA,MAAA;AAAA,MACA,aAAA;AAAA,MACA,UAAA;AAAA,MACA,cAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC
|
|
1
|
+
{"version":3,"file":"schedulerServiceFactory.cjs.js","sources":["../../../src/entrypoints/scheduler/schedulerServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { metricsServiceRef } from '@backstage/backend-plugin-api/alpha';\nimport { DefaultSchedulerService } from './lib/DefaultSchedulerService';\n\n/**\n * Scheduling of distributed background tasks.\n *\n * See {@link @backstage/code-plugin-api#SchedulerService}\n * and {@link https://backstage.io/docs/backend-system/core-services/scheduler | the service docs}\n * for more information.\n *\n * @public\n */\nexport const schedulerServiceFactory = createServiceFactory({\n service: coreServices.scheduler,\n deps: {\n database: coreServices.database,\n logger: coreServices.logger,\n rootLifecycle: coreServices.rootLifecycle,\n httpRouter: coreServices.httpRouter,\n pluginMetadata: coreServices.pluginMetadata,\n metrics: metricsServiceRef,\n },\n async factory({\n database,\n logger,\n rootLifecycle,\n httpRouter,\n pluginMetadata,\n metrics,\n }) {\n return DefaultSchedulerService.create({\n database,\n logger,\n rootLifecycle,\n httpRouter,\n pluginMetadata,\n metrics,\n });\n },\n});\n"],"names":["createServiceFactory","coreServices","metricsServiceRef","DefaultSchedulerService"],"mappings":";;;;;;AAgCO,MAAM,0BAA0BA,qCAAA,CAAqB;AAAA,EAC1D,SAASC,6BAAA,CAAa,SAAA;AAAA,EACtB,IAAA,EAAM;AAAA,IACJ,UAAUA,6BAAA,CAAa,QAAA;AAAA,IACvB,QAAQA,6BAAA,CAAa,MAAA;AAAA,IACrB,eAAeA,6BAAA,CAAa,aAAA;AAAA,IAC5B,YAAYA,6BAAA,CAAa,UAAA;AAAA,IACzB,gBAAgBA,6BAAA,CAAa,cAAA;AAAA,IAC7B,OAAA,EAASC;AAAA,GACX;AAAA,EACA,MAAM,OAAA,CAAQ;AAAA,IACZ,QAAA;AAAA,IACA,MAAA;AAAA,IACA,aAAA;AAAA,IACA,UAAA;AAAA,IACA,cAAA;AAAA,IACA;AAAA,GACF,EAAG;AACD,IAAA,OAAOC,gDAAwB,MAAA,CAAO;AAAA,MACpC,QAAA;AAAA,MACA,MAAA;AAAA,MACA,aAAA;AAAA,MACA,UAAA;AAAA,MACA,cAAA;AAAA,MACA;AAAA,KACD,CAAA;AAAA,EACH;AACF,CAAC;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AwsCodeCommitUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchOptions,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport {\n AwsCodeCommitIntegration,\n ScmIntegrations,\n} from '@backstage/integration';\nimport { toError, ForwardedError, NotModifiedError } from '@backstage/errors';\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport {\n CodeCommitClient,\n GetFileCommand,\n GetFileCommandInput,\n GetFileCommandOutput,\n GetFolderCommand,\n} from '@aws-sdk/client-codecommit';\nimport { AwsCredentialIdentityProvider } from '@aws-sdk/types';\nimport { Readable } from 'node:stream';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport { relative } from 'node:path/posix';\nimport { AbortController } from '@aws-sdk/abort-controller';\nimport { hasDotPathSegments } from './util';\n\nexport function parseUrl(\n url: string,\n requireGitPath: boolean = false,\n): {\n path: string;\n repositoryName: string;\n region: string;\n commitSpecifier?: string;\n} {\n const parsedUrl = new URL(url);\n\n if (parsedUrl.pathname.includes('/files/edit/')) {\n throw new Error(\n 'Please provide the view url to yaml file from CodeCommit, not the edit url',\n );\n }\n if (requireGitPath && !parsedUrl.pathname.includes('/browse/')) {\n throw new Error('Please provide full path to yaml file from CodeCommit');\n }\n\n const hostMatch = parsedUrl.host.match(\n /^([^\\.]+)\\.console\\.aws\\.amazon\\.com$/,\n );\n if (!hostMatch) {\n throw new Error(\n `Invalid AWS CodeCommit URL (unexpected host format): ${url}`,\n );\n }\n const [, region] = hostMatch;\n\n const pathMatch = parsedUrl.pathname.match(\n /^\\/codesuite\\/codecommit\\/repositories\\/([^\\/]+)\\/browse\\/((.*)\\/)?--\\/(.*)$/,\n );\n\n if (!pathMatch) {\n if (!requireGitPath) {\n const pathname = parsedUrl.pathname\n .split('/--/')[0]\n .replace('/codesuite/codecommit/repositories/', '');\n const [repositoryName, commitSpecifier] = pathname.split('/browse');\n\n return {\n region,\n repositoryName: repositoryName.replace(/^\\/|\\/$/g, ''),\n path: '/',\n commitSpecifier:\n commitSpecifier === ''\n ? undefined\n : commitSpecifier?.replace(/^\\/|\\/$/g, ''),\n };\n }\n throw new Error(\n `Invalid AWS CodeCommit URL (unexpected path format): ${url}`,\n );\n }\n const [, repositoryName, , commitSpecifier, path] = pathMatch;\n\n return {\n region,\n repositoryName,\n path,\n // the commitSpecifier is passed to AWS SDK which does not allow empty strings so replace empty string with undefined\n commitSpecifier: commitSpecifier === '' ? undefined : commitSpecifier,\n };\n}\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for AWS CodeCommit.\n *\n * @public\n */\nexport class AwsCodeCommitUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n const credsManager = DefaultAwsCredentialsManager.fromConfig(config);\n\n return integrations.awsCodeCommit.list().map(integration => {\n const reader = new AwsCodeCommitUrlReader(credsManager, integration, {\n treeResponseFactory,\n });\n const predicate = (url: URL) => {\n return (\n url.host.endsWith(integration.config.host) &&\n url.pathname.startsWith('/codesuite/codecommit')\n );\n };\n\n return { reader, predicate };\n });\n };\n\n private readonly credsManager: AwsCredentialsManager;\n private readonly integration: AwsCodeCommitIntegration;\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n };\n\n constructor(\n credsManager: AwsCredentialsManager,\n integration: AwsCodeCommitIntegration,\n deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {\n this.credsManager = credsManager;\n this.integration = integration;\n this.deps = deps;\n }\n\n /**\n * If accessKeyId and secretAccessKey are missing, the standard credentials provider chain will be used:\n * https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html\n */\n private static buildStaticCredentials(\n accessKeyId: string,\n secretAccessKey: string,\n ): AwsCredentialIdentityProvider {\n return async () => {\n return {\n accessKeyId,\n secretAccessKey,\n };\n };\n }\n\n private static async buildCredentials(\n credsManager: AwsCredentialsManager,\n region: string,\n integration?: AwsCodeCommitIntegration,\n ): Promise<AwsCredentialIdentityProvider> {\n // Fall back to the default credential chain if neither account ID\n // nor explicit credentials are provided\n if (!integration) {\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n const accessKeyId = integration.config.accessKeyId;\n const secretAccessKey = integration.config.secretAccessKey;\n const roleArn = integration.config.roleArn;\n\n if (accessKeyId && secretAccessKey) {\n const explicitCredentials = AwsCodeCommitUrlReader.buildStaticCredentials(\n accessKeyId,\n secretAccessKey,\n );\n if (roleArn) {\n return fromTemporaryCredentials({\n masterCredentials: explicitCredentials,\n params: {\n RoleSessionName: 'backstage-aws-code-commit-url-reader',\n RoleArn: roleArn,\n ExternalId: integration.config.externalId,\n },\n clientConfig: { region },\n });\n }\n return explicitCredentials;\n }\n\n if (roleArn) {\n let masterCredentials: AwsCredentialIdentityProvider;\n try {\n masterCredentials = (\n await credsManager.getCredentialProvider({ arn: roleArn })\n ).sdkCredentialProvider;\n } catch {\n // No account-specific config for this ARN; fall back to default credentials\n masterCredentials = (await credsManager.getCredentialProvider())\n .sdkCredentialProvider;\n }\n return fromTemporaryCredentials({\n masterCredentials,\n params: {\n RoleSessionName: 'backstage-aws-code-commit-url-reader',\n RoleArn: roleArn,\n ExternalId: integration.config.externalId,\n },\n clientConfig: { region },\n });\n }\n\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n private async buildCodeCommitClient(\n credsManager: AwsCredentialsManager,\n region: string,\n integration: AwsCodeCommitIntegration,\n ): Promise<CodeCommitClient> {\n const credentials = await AwsCodeCommitUrlReader.buildCredentials(\n credsManager,\n region,\n integration,\n );\n\n const codeCommit = new CodeCommitClient({\n customUserAgent: 'backstage-aws-codecommit-url-reader',\n region: region,\n credentials: credentials,\n });\n return codeCommit;\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n // etag and lastModifiedAfter are not supported by the CodeCommit API\n try {\n const { path, repositoryName, region, commitSpecifier } = parseUrl(\n url,\n true,\n );\n const codeCommitClient = await this.buildCodeCommitClient(\n this.credsManager,\n region,\n this.integration,\n );\n const abortController = new AbortController();\n\n const input: GetFileCommandInput = {\n repositoryName: repositoryName,\n commitSpecifier: commitSpecifier,\n filePath: path,\n };\n\n options?.signal?.addEventListener('abort', () => abortController.abort());\n const getObjectCommand = new GetFileCommand(input);\n const response: GetFileCommandOutput = await codeCommitClient.send(\n getObjectCommand,\n {\n abortSignal: abortController.signal,\n },\n );\n\n if (options?.etag && options.etag === response.commitId) {\n throw new NotModifiedError();\n }\n\n return ReadUrlResponseFactory.fromReadable(\n Readable.from([response?.fileContent]),\n {\n etag: response.commitId,\n },\n );\n } catch (e) {\n if (e.$metadata && e.$metadata.httpStatusCode === 304) {\n throw new NotModifiedError();\n }\n if (e.name && e.name === 'NotModifiedError') {\n throw new NotModifiedError();\n }\n\n throw new ForwardedError('Could not retrieve file from CodeCommit', e);\n }\n }\n\n async readTreePath(\n codeCommitClient: CodeCommitClient,\n abortSignal: any,\n path: string,\n repositoryName: string,\n commitSpecifier?: string,\n etag?: string,\n ): Promise<string[]> {\n const getFolderCommand = new GetFolderCommand({\n folderPath: path,\n repositoryName: repositoryName,\n commitSpecifier: commitSpecifier,\n });\n const response = await codeCommitClient.send(getFolderCommand, {\n abortSignal: abortSignal,\n });\n\n if (etag && etag === response.commitId) {\n throw new NotModifiedError();\n }\n\n const output: string[] = [];\n if (response.files) {\n response.files.forEach(file => {\n if (file.absolutePath) {\n output.push(file.absolutePath);\n }\n });\n }\n if (!response.subFolders) {\n return output;\n }\n\n for (const subFolder of response.subFolders) {\n if (subFolder.absolutePath) {\n output.push(\n ...(await this.readTreePath(\n codeCommitClient,\n abortSignal,\n subFolder.absolutePath,\n repositoryName,\n commitSpecifier,\n etag,\n )),\n );\n }\n }\n return output;\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n // url: https://eu-west-1.console.aws.amazon.com/codesuite/codecommit/repositories/test-stijn-delete-techdocs/browse?region=eu-west-1\n try {\n const { path, repositoryName, region, commitSpecifier } = parseUrl(url);\n const codeCommitClient = await this.buildCodeCommitClient(\n this.credsManager,\n region,\n this.integration,\n );\n\n const abortController = new AbortController();\n options?.signal?.addEventListener('abort', () => abortController.abort());\n\n const allFiles: string[] = await this.readTreePath(\n codeCommitClient,\n abortController.signal,\n path,\n repositoryName,\n commitSpecifier,\n options?.etag,\n );\n const responses = [];\n\n for (let i = 0; i < allFiles.length; i++) {\n if (hasDotPathSegments(String(allFiles[i]))) {\n continue;\n }\n const getFileCommand = new GetFileCommand({\n repositoryName: repositoryName,\n filePath: String(allFiles[i]),\n commitSpecifier: commitSpecifier,\n });\n const response = await codeCommitClient.send(getFileCommand);\n const objectData = await Readable.from([response?.fileContent]);\n\n responses.push({\n data: objectData,\n path: relative(\n path.startsWith('/') ? path : `/${path}`,\n allFiles[i].startsWith('/') ? allFiles[i] : `/${allFiles[i]}`,\n ),\n });\n }\n\n return await this.deps.treeResponseFactory.fromReadableArray(responses);\n } catch (e) {\n if (e.name && e.name === 'NotModifiedError') {\n throw new NotModifiedError();\n }\n throw new ForwardedError(\n 'Could not retrieve file tree from CodeCommit',\n e,\n );\n }\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const { path } = parseUrl(url, true);\n\n if (path.match(/[*?]/)) {\n throw new Error('Unsupported search pattern URL');\n }\n\n try {\n const data = await this.readUrl(url, options);\n\n return {\n files: [\n {\n url: url,\n content: data.buffer,\n lastModifiedAt: data.lastModifiedAt,\n },\n ],\n etag: data.etag ?? '',\n };\n } catch (e) {\n const error = toError(e);\n if (error.name === 'NotFoundError') {\n return {\n files: [],\n etag: '',\n };\n }\n throw error;\n }\n }\n\n toString() {\n const secretAccessKey = this.integration.config.secretAccessKey;\n return `awsCodeCommit{host=${this.integration.config.host},authed=${Boolean(\n secretAccessKey,\n )}}`;\n }\n}\n"],"names":["repositoryName","commitSpecifier","ScmIntegrations","DefaultAwsCredentialsManager","fromTemporaryCredentials","CodeCommitClient","abortController","AbortController","GetFileCommand","NotModifiedError","ReadUrlResponseFactory","Readable","ForwardedError","GetFolderCommand","hasDotPathSegments","relative","toError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AwsCodeCommitUrlReader.cjs.js","sources":["../../../../src/entrypoints/urlReader/lib/AwsCodeCommitUrlReader.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ReaderFactory, ReadTreeResponseFactory } from './types';\nimport {\n UrlReaderService,\n UrlReaderServiceReadTreeOptions,\n UrlReaderServiceReadTreeResponse,\n UrlReaderServiceReadUrlOptions,\n UrlReaderServiceReadUrlResponse,\n UrlReaderServiceSearchOptions,\n UrlReaderServiceSearchResponse,\n} from '@backstage/backend-plugin-api';\nimport {\n AwsCredentialsManager,\n DefaultAwsCredentialsManager,\n} from '@backstage/integration-aws-node';\nimport {\n AwsCodeCommitIntegration,\n ScmIntegrations,\n} from '@backstage/integration';\nimport { toError, ForwardedError, NotModifiedError } from '@backstage/errors';\nimport { fromTemporaryCredentials } from '@aws-sdk/credential-providers';\nimport {\n CodeCommitClient,\n GetFileCommand,\n GetFileCommandInput,\n GetFileCommandOutput,\n GetFolderCommand,\n} from '@aws-sdk/client-codecommit';\nimport { AwsCredentialIdentityProvider } from '@aws-sdk/types';\nimport { Readable } from 'node:stream';\nimport { ReadUrlResponseFactory } from './ReadUrlResponseFactory';\nimport { relative } from 'node:path/posix';\nimport { AbortController } from '@aws-sdk/abort-controller';\nimport { hasDotPathSegments } from './util';\n\nexport function parseUrl(\n url: string,\n requireGitPath: boolean = false,\n): {\n path: string;\n repositoryName: string;\n region: string;\n commitSpecifier?: string;\n} {\n const parsedUrl = new URL(url);\n\n if (parsedUrl.pathname.includes('/files/edit/')) {\n throw new Error(\n 'Please provide the view url to yaml file from CodeCommit, not the edit url',\n );\n }\n if (requireGitPath && !parsedUrl.pathname.includes('/browse/')) {\n throw new Error('Please provide full path to yaml file from CodeCommit');\n }\n\n const hostMatch = parsedUrl.host.match(\n /^([^\\.]+)\\.console\\.aws\\.amazon\\.com$/,\n );\n if (!hostMatch) {\n throw new Error(\n `Invalid AWS CodeCommit URL (unexpected host format): ${url}`,\n );\n }\n const [, region] = hostMatch;\n\n const pathMatch = parsedUrl.pathname.match(\n /^\\/codesuite\\/codecommit\\/repositories\\/([^\\/]+)\\/browse\\/((.*)\\/)?--\\/(.*)$/,\n );\n\n if (!pathMatch) {\n if (!requireGitPath) {\n const pathname = parsedUrl.pathname\n .split('/--/')[0]\n .replace('/codesuite/codecommit/repositories/', '');\n const [repositoryName, commitSpecifier] = pathname.split('/browse');\n\n return {\n region,\n repositoryName: repositoryName.replace(/^\\/|\\/$/g, ''),\n path: '/',\n commitSpecifier:\n commitSpecifier === ''\n ? undefined\n : commitSpecifier?.replace(/^\\/|\\/$/g, ''),\n };\n }\n throw new Error(\n `Invalid AWS CodeCommit URL (unexpected path format): ${url}`,\n );\n }\n const [, repositoryName, , commitSpecifier, path] = pathMatch;\n\n return {\n region,\n repositoryName,\n path,\n // the commitSpecifier is passed to AWS SDK which does not allow empty strings so replace empty string with undefined\n commitSpecifier: commitSpecifier === '' ? undefined : commitSpecifier,\n };\n}\n\n/**\n * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for AWS CodeCommit.\n *\n * @public\n */\nexport class AwsCodeCommitUrlReader implements UrlReaderService {\n static factory: ReaderFactory = ({ config, treeResponseFactory }) => {\n const integrations = ScmIntegrations.fromConfig(config);\n const credsManager = DefaultAwsCredentialsManager.fromConfig(config);\n\n return integrations.awsCodeCommit.list().map(integration => {\n const reader = new AwsCodeCommitUrlReader(credsManager, integration, {\n treeResponseFactory,\n });\n const predicate = (url: URL) => {\n return (\n url.host.endsWith(integration.config.host) &&\n url.pathname.startsWith('/codesuite/codecommit')\n );\n };\n\n return { reader, predicate };\n });\n };\n\n private readonly credsManager: AwsCredentialsManager;\n private readonly integration: AwsCodeCommitIntegration;\n private readonly deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n };\n\n constructor(\n credsManager: AwsCredentialsManager,\n integration: AwsCodeCommitIntegration,\n deps: {\n treeResponseFactory: ReadTreeResponseFactory;\n },\n ) {\n this.credsManager = credsManager;\n this.integration = integration;\n this.deps = deps;\n }\n\n /**\n * If accessKeyId and secretAccessKey are missing, the standard credentials provider chain will be used:\n * https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html\n */\n private static buildStaticCredentials(\n accessKeyId: string,\n secretAccessKey: string,\n ): AwsCredentialIdentityProvider {\n return async () => {\n return {\n accessKeyId,\n secretAccessKey,\n };\n };\n }\n\n private static async buildCredentials(\n credsManager: AwsCredentialsManager,\n region: string,\n integration?: AwsCodeCommitIntegration,\n ): Promise<AwsCredentialIdentityProvider> {\n // Fall back to the default credential chain if neither account ID\n // nor explicit credentials are provided\n if (!integration) {\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n const accessKeyId = integration.config.accessKeyId;\n const secretAccessKey = integration.config.secretAccessKey;\n const roleArn = integration.config.roleArn;\n\n if (accessKeyId && secretAccessKey) {\n const explicitCredentials = AwsCodeCommitUrlReader.buildStaticCredentials(\n accessKeyId,\n secretAccessKey,\n );\n if (roleArn) {\n return fromTemporaryCredentials({\n masterCredentials: explicitCredentials,\n params: {\n RoleSessionName: 'backstage-aws-code-commit-url-reader',\n RoleArn: roleArn,\n ExternalId: integration.config.externalId,\n },\n clientConfig: { region },\n });\n }\n return explicitCredentials;\n }\n\n if (roleArn) {\n let masterCredentials: AwsCredentialIdentityProvider;\n try {\n masterCredentials = (\n await credsManager.getCredentialProvider({ arn: roleArn })\n ).sdkCredentialProvider;\n } catch {\n // No account-specific config for this ARN; fall back to default credentials\n masterCredentials = (await credsManager.getCredentialProvider())\n .sdkCredentialProvider;\n }\n return fromTemporaryCredentials({\n masterCredentials,\n params: {\n RoleSessionName: 'backstage-aws-code-commit-url-reader',\n RoleArn: roleArn,\n ExternalId: integration.config.externalId,\n },\n clientConfig: { region },\n });\n }\n\n return (await credsManager.getCredentialProvider()).sdkCredentialProvider;\n }\n\n private async buildCodeCommitClient(\n credsManager: AwsCredentialsManager,\n region: string,\n integration: AwsCodeCommitIntegration,\n ): Promise<CodeCommitClient> {\n const credentials = await AwsCodeCommitUrlReader.buildCredentials(\n credsManager,\n region,\n integration,\n );\n\n const codeCommit = new CodeCommitClient({\n customUserAgent: 'backstage-aws-codecommit-url-reader',\n region: region,\n credentials: credentials,\n });\n return codeCommit;\n }\n\n async readUrl(\n url: string,\n options?: UrlReaderServiceReadUrlOptions,\n ): Promise<UrlReaderServiceReadUrlResponse> {\n // etag and lastModifiedAfter are not supported by the CodeCommit API\n try {\n const { path, repositoryName, region, commitSpecifier } = parseUrl(\n url,\n true,\n );\n const codeCommitClient = await this.buildCodeCommitClient(\n this.credsManager,\n region,\n this.integration,\n );\n const abortController = new AbortController();\n\n const input: GetFileCommandInput = {\n repositoryName: repositoryName,\n commitSpecifier: commitSpecifier,\n filePath: path,\n };\n\n options?.signal?.addEventListener('abort', () => abortController.abort());\n const getObjectCommand = new GetFileCommand(input);\n const response: GetFileCommandOutput = await codeCommitClient.send(\n getObjectCommand,\n {\n abortSignal: abortController.signal,\n },\n );\n\n if (options?.etag && options.etag === response.commitId) {\n throw new NotModifiedError();\n }\n\n return ReadUrlResponseFactory.fromReadable(\n Readable.from([response?.fileContent]),\n {\n etag: response.commitId,\n },\n );\n } catch (e) {\n if (e.$metadata && e.$metadata.httpStatusCode === 304) {\n throw new NotModifiedError();\n }\n if (e.name && e.name === 'NotModifiedError') {\n throw new NotModifiedError();\n }\n\n throw new ForwardedError('Could not retrieve file from CodeCommit', e);\n }\n }\n\n async readTreePath(\n codeCommitClient: CodeCommitClient,\n abortSignal: any,\n path: string,\n repositoryName: string,\n commitSpecifier?: string,\n etag?: string,\n ): Promise<string[]> {\n const getFolderCommand = new GetFolderCommand({\n folderPath: path,\n repositoryName: repositoryName,\n commitSpecifier: commitSpecifier,\n });\n const response = await codeCommitClient.send(getFolderCommand, {\n abortSignal: abortSignal,\n });\n\n if (etag && etag === response.commitId) {\n throw new NotModifiedError();\n }\n\n const output: string[] = [];\n if (response.files) {\n response.files.forEach(file => {\n if (file.absolutePath) {\n output.push(file.absolutePath);\n }\n });\n }\n if (!response.subFolders) {\n return output;\n }\n\n for (const subFolder of response.subFolders) {\n if (subFolder.absolutePath) {\n output.push(\n ...(await this.readTreePath(\n codeCommitClient,\n abortSignal,\n subFolder.absolutePath,\n repositoryName,\n commitSpecifier,\n etag,\n )),\n );\n }\n }\n return output;\n }\n\n async readTree(\n url: string,\n options?: UrlReaderServiceReadTreeOptions,\n ): Promise<UrlReaderServiceReadTreeResponse> {\n // url: https://eu-west-1.console.aws.amazon.com/codesuite/codecommit/repositories/test-stijn-delete-techdocs/browse?region=eu-west-1\n try {\n const { path, repositoryName, region, commitSpecifier } = parseUrl(url);\n const codeCommitClient = await this.buildCodeCommitClient(\n this.credsManager,\n region,\n this.integration,\n );\n\n const abortController = new AbortController();\n options?.signal?.addEventListener('abort', () => abortController.abort());\n\n const allFiles: string[] = await this.readTreePath(\n codeCommitClient,\n abortController.signal,\n path,\n repositoryName,\n commitSpecifier,\n options?.etag,\n );\n const responses = [];\n\n for (let i = 0; i < allFiles.length; i++) {\n if (hasDotPathSegments(String(allFiles[i]))) {\n continue;\n }\n const getFileCommand = new GetFileCommand({\n repositoryName: repositoryName,\n filePath: String(allFiles[i]),\n commitSpecifier: commitSpecifier,\n });\n const response = await codeCommitClient.send(getFileCommand);\n const objectData = await Readable.from([response?.fileContent]);\n\n responses.push({\n data: objectData,\n path: relative(\n path.startsWith('/') ? path : `/${path}`,\n allFiles[i].startsWith('/') ? allFiles[i] : `/${allFiles[i]}`,\n ),\n });\n }\n\n return await this.deps.treeResponseFactory.fromReadableArray(responses);\n } catch (e) {\n if (e.name && e.name === 'NotModifiedError') {\n throw new NotModifiedError();\n }\n throw new ForwardedError(\n 'Could not retrieve file tree from CodeCommit',\n e,\n );\n }\n }\n\n async search(\n url: string,\n options?: UrlReaderServiceSearchOptions,\n ): Promise<UrlReaderServiceSearchResponse> {\n const { path } = parseUrl(url, true);\n\n if (path.match(/[*?]/)) {\n throw new Error('Unsupported search pattern URL');\n }\n\n try {\n const data = await this.readUrl(url, options);\n\n return {\n files: [\n {\n url: url,\n content: data.buffer,\n lastModifiedAt: data.lastModifiedAt,\n },\n ],\n etag: data.etag ?? '',\n };\n } catch (e) {\n const error = toError(e);\n if (error.name === 'NotFoundError') {\n return {\n files: [],\n etag: '',\n };\n }\n throw error;\n }\n }\n\n toString() {\n const secretAccessKey = this.integration.config.secretAccessKey;\n return `awsCodeCommit{host=${this.integration.config.host},authed=${Boolean(\n secretAccessKey,\n )}}`;\n }\n}\n"],"names":["repositoryName","commitSpecifier","ScmIntegrations","DefaultAwsCredentialsManager","fromTemporaryCredentials","CodeCommitClient","abortController","AbortController","GetFileCommand","NotModifiedError","ReadUrlResponseFactory","Readable","ForwardedError","GetFolderCommand","hasDotPathSegments","relative","toError"],"mappings":"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"}
|