@backstage/plugin-scaffolder-backend 4.1.0-next.0 → 4.1.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.
Files changed (41) hide show
  1. package/CHANGELOG.md +23 -11
  2. package/README.md +0 -23
  3. package/config.schema.json +7 -63
  4. package/dist/ScaffolderPlugin.cjs.js +9 -2
  5. package/dist/ScaffolderPlugin.cjs.js.map +1 -1
  6. package/dist/actions/createDryRunTemplateAction.cjs.js +0 -2
  7. package/dist/actions/createDryRunTemplateAction.cjs.js.map +1 -1
  8. package/dist/index.d.ts +4 -0
  9. package/dist/scaffolder/actions/builtin/fetch/assertScmUserCredentials.cjs.js +34 -0
  10. package/dist/scaffolder/actions/builtin/fetch/assertScmUserCredentials.cjs.js.map +1 -0
  11. package/dist/scaffolder/actions/builtin/fetch/plain.cjs.js +9 -1
  12. package/dist/scaffolder/actions/builtin/fetch/plain.cjs.js.map +1 -1
  13. package/dist/scaffolder/actions/builtin/fetch/plainFile.cjs.js +9 -1
  14. package/dist/scaffolder/actions/builtin/fetch/plainFile.cjs.js.map +1 -1
  15. package/dist/scaffolder/actions/builtin/fetch/template.cjs.js +8 -0
  16. package/dist/scaffolder/actions/builtin/fetch/template.cjs.js.map +1 -1
  17. package/dist/scaffolder/actions/builtin/fetch/templateFile.cjs.js +8 -0
  18. package/dist/scaffolder/actions/builtin/fetch/templateFile.cjs.js.map +1 -1
  19. package/dist/scaffolder/tasks/DatabaseTaskStore.cjs.js +53 -78
  20. package/dist/scaffolder/tasks/DatabaseTaskStore.cjs.js.map +1 -1
  21. package/dist/scaffolder/tasks/DatabaseWorkspaceProvider.cjs.js +23 -0
  22. package/dist/scaffolder/tasks/DatabaseWorkspaceProvider.cjs.js.map +1 -0
  23. package/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js +130 -91
  24. package/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js.map +1 -1
  25. package/dist/scaffolder/tasks/StorageTaskBroker.cjs.js +29 -53
  26. package/dist/scaffolder/tasks/StorageTaskBroker.cjs.js.map +1 -1
  27. package/dist/scaffolder/tasks/WorkspaceService.cjs.js +18 -26
  28. package/dist/scaffolder/tasks/WorkspaceService.cjs.js.map +1 -1
  29. package/dist/scaffolder/tasks/logger.cjs.js +101 -7
  30. package/dist/scaffolder/tasks/logger.cjs.js.map +1 -1
  31. package/dist/scaffolder/tasks/taskRecoveryHelper.cjs.js +0 -4
  32. package/dist/scaffolder/tasks/taskRecoveryHelper.cjs.js.map +1 -1
  33. package/dist/schema/openapi/generated/router.cjs.js +6 -6
  34. package/dist/schema/openapi/generated/router.cjs.js.map +1 -1
  35. package/dist/service/router.cjs.js +22 -9
  36. package/dist/service/router.cjs.js.map +1 -1
  37. package/dist/service/rules.cjs.js +12 -0
  38. package/dist/service/rules.cjs.js.map +1 -1
  39. package/dist/util/checkPermissions.cjs.js +3 -0
  40. package/dist/util/checkPermissions.cjs.js.map +1 -1
  41. package/package.json +20 -20
@@ -1 +1 @@
1
- {"version":3,"file":"templateFile.cjs.js","sources":["../../../../../src/scaffolder/actions/builtin/fetch/templateFile.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { UrlReaderService } from '@backstage/backend-plugin-api';\nimport { ScmIntegrations } from '@backstage/integration';\nimport {\n createTemplateAction,\n fetchFile,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport path from 'node:path';\nimport { examples } from './templateFile.examples';\nimport { createTemplateFileActionHandler } from './templateFileActionHandler';\nimport { collectActionTemplateCapabilities } from './templateActionHandler';\n\n/**\n * Downloads a single file and templates variables into file.\n * Then places the result in the workspace, or optionally in a subdirectory\n * specified by the 'targetPath' input option.\n * @public\n */\nexport function createFetchTemplateFileAction(options: {\n reader: UrlReaderService;\n integrations: ScmIntegrations;\n additionalTemplateFilters?: Record<string, TemplateFilter>;\n additionalTemplateGlobals?: Record<string, TemplateGlobal>;\n}) {\n const templateCapabilities = collectActionTemplateCapabilities(options);\n\n return createTemplateAction({\n id: 'fetch:template:file',\n description: 'Downloads single file and places it in the workspace.',\n examples,\n schema: {\n input: {\n url: z =>\n z.string({\n description:\n 'Relative path or absolute URL pointing to the single file to fetch.',\n }),\n targetPath: z =>\n z.string({\n description:\n 'Target path within the working directory to download the file as.',\n }),\n values: z =>\n z\n .record(z.any(), {\n description: 'Values to pass on to the templating engine',\n })\n .optional(),\n cookiecutterCompat: z =>\n z\n .boolean({\n description:\n 'Enable features to maximise compatibility with templates built for fetch:cookiecutter',\n })\n .optional(),\n replace: z =>\n z\n .boolean({\n description:\n 'If set, replace file in targetPath instead of overwriting existing one.',\n })\n .optional(),\n trimBlocks: z =>\n z\n .boolean({\n description:\n 'If set, the first newline after a block is removed (block, not variable tag).',\n })\n .optional(),\n lstripBlocks: z =>\n z\n .boolean({\n description:\n 'If set, leading spaces and tabs are stripped from the start of a line to a block.',\n })\n .optional(),\n token: z =>\n z\n .string({\n description:\n 'An optional token to use for authentication when reading the resources.',\n })\n .optional(),\n },\n },\n supportsDryRun: true,\n handler: ctx =>\n createTemplateFileActionHandler({\n ctx,\n resolveTemplateFile: async () => {\n ctx.logger.info('Fetching template file content from remote URL');\n\n const workDir = await ctx.createTemporaryDirectory();\n // Write to a tmp file, render the template, then copy to workspace.\n const tmpFilePath = path.join(workDir, 'tmp');\n\n await fetchFile({\n baseUrl: ctx.templateInfo?.baseUrl,\n fetchUrl: ctx.input.url,\n outputPath: tmpFilePath,\n token: ctx.input.token,\n ...options,\n });\n return tmpFilePath;\n },\n ...options,\n templateCapabilities,\n }),\n });\n}\n"],"names":["collectActionTemplateCapabilities","createTemplateAction","examples","createTemplateFileActionHandler","path","fetchFile"],"mappings":";;;;;;;;;;;;AAmCO,SAAS,8BAA8B,OAAA,EAK3C;AACD,EAAA,MAAM,oBAAA,GAAuBA,wDAAkC,OAAO,CAAA;AAEtE,EAAA,OAAOC,yCAAA,CAAqB;AAAA,IAC1B,EAAA,EAAI,qBAAA;AAAA,IACJ,WAAA,EAAa,uDAAA;AAAA,cACbC,8BAAA;AAAA,IACA,MAAA,EAAQ;AAAA,MACN,KAAA,EAAO;AAAA,QACL,GAAA,EAAK,CAAA,CAAA,KACH,CAAA,CAAE,MAAA,CAAO;AAAA,UACP,WAAA,EACE;AAAA,SACH,CAAA;AAAA,QACH,UAAA,EAAY,CAAA,CAAA,KACV,CAAA,CAAE,MAAA,CAAO;AAAA,UACP,WAAA,EACE;AAAA,SACH,CAAA;AAAA,QACH,QAAQ,CAAA,CAAA,KACN,CAAA,CACG,MAAA,CAAO,CAAA,CAAE,KAAI,EAAG;AAAA,UACf,WAAA,EAAa;AAAA,SACd,EACA,QAAA,EAAS;AAAA,QACd,kBAAA,EAAoB,CAAA,CAAA,KAClB,CAAA,CACG,OAAA,CAAQ;AAAA,UACP,WAAA,EACE;AAAA,SACH,EACA,QAAA,EAAS;AAAA,QACd,OAAA,EAAS,CAAA,CAAA,KACP,CAAA,CACG,OAAA,CAAQ;AAAA,UACP,WAAA,EACE;AAAA,SACH,EACA,QAAA,EAAS;AAAA,QACd,UAAA,EAAY,CAAA,CAAA,KACV,CAAA,CACG,OAAA,CAAQ;AAAA,UACP,WAAA,EACE;AAAA,SACH,EACA,QAAA,EAAS;AAAA,QACd,YAAA,EAAc,CAAA,CAAA,KACZ,CAAA,CACG,OAAA,CAAQ;AAAA,UACP,WAAA,EACE;AAAA,SACH,EACA,QAAA,EAAS;AAAA,QACd,KAAA,EAAO,CAAA,CAAA,KACL,CAAA,CACG,MAAA,CAAO;AAAA,UACN,WAAA,EACE;AAAA,SACH,EACA,QAAA;AAAS;AAChB,KACF;AAAA,IACA,cAAA,EAAgB,IAAA;AAAA,IAChB,OAAA,EAAS,SACPC,yDAAA,CAAgC;AAAA,MAC9B,GAAA;AAAA,MACA,qBAAqB,YAAY;AAC/B,QAAA,GAAA,CAAI,MAAA,CAAO,KAAK,gDAAgD,CAAA;AAEhE,QAAA,MAAM,OAAA,GAAU,MAAM,GAAA,CAAI,wBAAA,EAAyB;AAEnD,QAAA,MAAM,WAAA,GAAcC,qBAAA,CAAK,IAAA,CAAK,OAAA,EAAS,KAAK,CAAA;AAE5C,QAAA,MAAMC,8BAAA,CAAU;AAAA,UACd,OAAA,EAAS,IAAI,YAAA,EAAc,OAAA;AAAA,UAC3B,QAAA,EAAU,IAAI,KAAA,CAAM,GAAA;AAAA,UACpB,UAAA,EAAY,WAAA;AAAA,UACZ,KAAA,EAAO,IAAI,KAAA,CAAM,KAAA;AAAA,UACjB,GAAG;AAAA,SACJ,CAAA;AACD,QAAA,OAAO,WAAA;AAAA,MACT,CAAA;AAAA,MACA,GAAG,OAAA;AAAA,MACH;AAAA,KACD;AAAA,GACJ,CAAA;AACH;;;;"}
1
+ {"version":3,"file":"templateFile.cjs.js","sources":["../../../../../src/scaffolder/actions/builtin/fetch/templateFile.ts"],"sourcesContent":["/*\n * Copyright 2024 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 { UrlReaderService } from '@backstage/backend-plugin-api';\nimport { ScmIntegrations } from '@backstage/integration';\nimport {\n createTemplateAction,\n fetchFile,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport path from 'node:path';\nimport { examples } from './templateFile.examples';\nimport { assertScmUserCredentials } from './assertScmUserCredentials';\nimport { createTemplateFileActionHandler } from './templateFileActionHandler';\nimport { collectActionTemplateCapabilities } from './templateActionHandler';\n\n/**\n * Downloads a single file and templates variables into file.\n * Then places the result in the workspace, or optionally in a subdirectory\n * specified by the 'targetPath' input option.\n * @public\n */\nexport function createFetchTemplateFileAction(options: {\n reader: UrlReaderService;\n integrations: ScmIntegrations;\n requireScmUserCredentials?: boolean;\n additionalTemplateFilters?: Record<string, TemplateFilter>;\n additionalTemplateGlobals?: Record<string, TemplateGlobal>;\n}) {\n const templateCapabilities = collectActionTemplateCapabilities(options);\n\n return createTemplateAction({\n id: 'fetch:template:file',\n description: 'Downloads single file and places it in the workspace.',\n examples,\n schema: {\n input: {\n url: z =>\n z.string({\n description:\n 'Relative path or absolute URL pointing to the single file to fetch.',\n }),\n targetPath: z =>\n z.string({\n description:\n 'Target path within the working directory to download the file as.',\n }),\n values: z =>\n z\n .record(z.any(), {\n description: 'Values to pass on to the templating engine',\n })\n .optional(),\n cookiecutterCompat: z =>\n z\n .boolean({\n description:\n 'Enable features to maximise compatibility with templates built for fetch:cookiecutter',\n })\n .optional(),\n replace: z =>\n z\n .boolean({\n description:\n 'If set, replace file in targetPath instead of overwriting existing one.',\n })\n .optional(),\n trimBlocks: z =>\n z\n .boolean({\n description:\n 'If set, the first newline after a block is removed (block, not variable tag).',\n })\n .optional(),\n lstripBlocks: z =>\n z\n .boolean({\n description:\n 'If set, leading spaces and tabs are stripped from the start of a line to a block.',\n })\n .optional(),\n token: z =>\n z\n .string({\n description:\n 'An optional token to use for authentication when reading the resources.',\n })\n .optional(),\n },\n },\n supportsDryRun: true,\n handler: ctx =>\n createTemplateFileActionHandler({\n ctx,\n resolveTemplateFile: async () => {\n ctx.logger.info('Fetching template file content from remote URL');\n\n assertScmUserCredentials({\n integrations: options.integrations,\n requireScmUserCredentials: options.requireScmUserCredentials,\n url: ctx.input.url,\n baseUrl: ctx.templateInfo?.baseUrl,\n token: ctx.input.token,\n });\n\n const workDir = await ctx.createTemporaryDirectory();\n // Write to a tmp file, render the template, then copy to workspace.\n const tmpFilePath = path.join(workDir, 'tmp');\n\n await fetchFile({\n baseUrl: ctx.templateInfo?.baseUrl,\n fetchUrl: ctx.input.url,\n outputPath: tmpFilePath,\n token: ctx.input.token,\n ...options,\n });\n return tmpFilePath;\n },\n ...options,\n templateCapabilities,\n }),\n });\n}\n"],"names":["collectActionTemplateCapabilities","createTemplateAction","examples","createTemplateFileActionHandler","assertScmUserCredentials","path","fetchFile"],"mappings":";;;;;;;;;;;;;AAoCO,SAAS,8BAA8B,OAAA,EAM3C;AACD,EAAA,MAAM,oBAAA,GAAuBA,wDAAkC,OAAO,CAAA;AAEtE,EAAA,OAAOC,yCAAA,CAAqB;AAAA,IAC1B,EAAA,EAAI,qBAAA;AAAA,IACJ,WAAA,EAAa,uDAAA;AAAA,cACbC,8BAAA;AAAA,IACA,MAAA,EAAQ;AAAA,MACN,KAAA,EAAO;AAAA,QACL,GAAA,EAAK,CAAA,CAAA,KACH,CAAA,CAAE,MAAA,CAAO;AAAA,UACP,WAAA,EACE;AAAA,SACH,CAAA;AAAA,QACH,UAAA,EAAY,CAAA,CAAA,KACV,CAAA,CAAE,MAAA,CAAO;AAAA,UACP,WAAA,EACE;AAAA,SACH,CAAA;AAAA,QACH,QAAQ,CAAA,CAAA,KACN,CAAA,CACG,MAAA,CAAO,CAAA,CAAE,KAAI,EAAG;AAAA,UACf,WAAA,EAAa;AAAA,SACd,EACA,QAAA,EAAS;AAAA,QACd,kBAAA,EAAoB,CAAA,CAAA,KAClB,CAAA,CACG,OAAA,CAAQ;AAAA,UACP,WAAA,EACE;AAAA,SACH,EACA,QAAA,EAAS;AAAA,QACd,OAAA,EAAS,CAAA,CAAA,KACP,CAAA,CACG,OAAA,CAAQ;AAAA,UACP,WAAA,EACE;AAAA,SACH,EACA,QAAA,EAAS;AAAA,QACd,UAAA,EAAY,CAAA,CAAA,KACV,CAAA,CACG,OAAA,CAAQ;AAAA,UACP,WAAA,EACE;AAAA,SACH,EACA,QAAA,EAAS;AAAA,QACd,YAAA,EAAc,CAAA,CAAA,KACZ,CAAA,CACG,OAAA,CAAQ;AAAA,UACP,WAAA,EACE;AAAA,SACH,EACA,QAAA,EAAS;AAAA,QACd,KAAA,EAAO,CAAA,CAAA,KACL,CAAA,CACG,MAAA,CAAO;AAAA,UACN,WAAA,EACE;AAAA,SACH,EACA,QAAA;AAAS;AAChB,KACF;AAAA,IACA,cAAA,EAAgB,IAAA;AAAA,IAChB,OAAA,EAAS,SACPC,yDAAA,CAAgC;AAAA,MAC9B,GAAA;AAAA,MACA,qBAAqB,YAAY;AAC/B,QAAA,GAAA,CAAI,MAAA,CAAO,KAAK,gDAAgD,CAAA;AAEhE,QAAAC,iDAAA,CAAyB;AAAA,UACvB,cAAc,OAAA,CAAQ,YAAA;AAAA,UACtB,2BAA2B,OAAA,CAAQ,yBAAA;AAAA,UACnC,GAAA,EAAK,IAAI,KAAA,CAAM,GAAA;AAAA,UACf,OAAA,EAAS,IAAI,YAAA,EAAc,OAAA;AAAA,UAC3B,KAAA,EAAO,IAAI,KAAA,CAAM;AAAA,SAClB,CAAA;AAED,QAAA,MAAM,OAAA,GAAU,MAAM,GAAA,CAAI,wBAAA,EAAyB;AAEnD,QAAA,MAAM,WAAA,GAAcC,qBAAA,CAAK,IAAA,CAAK,OAAA,EAAS,KAAK,CAAA;AAE5C,QAAA,MAAMC,8BAAA,CAAU;AAAA,UACd,OAAA,EAAS,IAAI,YAAA,EAAc,OAAA;AAAA,UAC3B,QAAA,EAAU,IAAI,KAAA,CAAM,GAAA;AAAA,UACpB,UAAA,EAAY,WAAA;AAAA,UACZ,KAAA,EAAO,IAAI,KAAA,CAAM,KAAA;AAAA,UACjB,GAAG;AAAA,SACJ,CAAA;AACD,QAAA,OAAO,WAAA;AAAA,MACT,CAAA;AAAA,MACA,GAAG,OAAA;AAAA,MACH;AAAA,KACD;AAAA,GACJ,CAAA;AACH;;;;"}
@@ -6,6 +6,7 @@ var node_crypto = require('node:crypto');
6
6
  var luxon = require('luxon');
7
7
  var taskRecoveryHelper = require('./taskRecoveryHelper.cjs.js');
8
8
  var dbUtil = require('./dbUtil.cjs.js');
9
+ var alpha = require('@backstage/plugin-scaffolder-node/alpha');
9
10
  var helpers = require('../../service/helpers.cjs.js');
10
11
  var pluginPermissionNode = require('@backstage/plugin-permission-node');
11
12
  var lodash = require('lodash');
@@ -32,16 +33,11 @@ const parseSqlDateToIsoString = (input) => {
32
33
  class DatabaseTaskStore {
33
34
  db;
34
35
  events;
35
- recoverTasksEnabled;
36
36
  static async create(options) {
37
37
  const { database } = options;
38
38
  const client = await this.getClient(database);
39
39
  await this.runMigrations(database, client);
40
- return new DatabaseTaskStore(
41
- client,
42
- options.events,
43
- options.recoverTasksEnabled ?? false
44
- );
40
+ return new DatabaseTaskStore(client, options.events);
45
41
  }
46
42
  isRecoverableTask(spec) {
47
43
  return ["startOver"].includes(
@@ -83,10 +79,9 @@ class DatabaseTaskStore {
83
79
  });
84
80
  }
85
81
  }
86
- constructor(client, events, recoverTasksEnabled) {
82
+ constructor(client, events) {
87
83
  this.db = client;
88
84
  this.events = events;
89
- this.recoverTasksEnabled = recoverTasksEnabled;
90
85
  }
91
86
  getState(task) {
92
87
  try {
@@ -168,14 +163,7 @@ class DatabaseTaskStore {
168
163
  queryBuilder.offset(pagination.offset);
169
164
  }
170
165
  const [results, [{ count }]] = await Promise.all([
171
- queryBuilder.select([
172
- "id",
173
- "spec",
174
- "status",
175
- "created_by",
176
- "last_heartbeat_at",
177
- "created_at"
178
- ]),
166
+ queryBuilder.select(),
179
167
  countQuery
180
168
  ]);
181
169
  const tasks = results.map((result) => ({
@@ -195,16 +183,7 @@ class DatabaseTaskStore {
195
183
  return { tasks, totalTasks };
196
184
  }
197
185
  async getTask(taskId) {
198
- const [result] = await this.db("tasks").where({ id: taskId }).select([
199
- "id",
200
- "spec",
201
- "status",
202
- "state",
203
- "last_heartbeat_at",
204
- "created_at",
205
- "created_by",
206
- "secrets"
207
- ]);
186
+ const [result] = await this.db("tasks").where({ id: taskId }).select();
208
187
  if (!result) {
209
188
  throw new errors.NotFoundError(`No task with id '${taskId}' found`);
210
189
  }
@@ -253,16 +232,7 @@ class DatabaseTaskStore {
253
232
  return this.db.transaction(async (tx) => {
254
233
  const [task] = await tx("tasks").where({
255
234
  status: "open"
256
- }).limit(1).select([
257
- "id",
258
- "spec",
259
- "status",
260
- "state",
261
- "last_heartbeat_at",
262
- "created_at",
263
- "created_by",
264
- "secrets"
265
- ]);
235
+ }).limit(1).select();
266
236
  if (!task) {
267
237
  return void 0;
268
238
  }
@@ -270,11 +240,8 @@ class DatabaseTaskStore {
270
240
  const updateCount = await tx("tasks").where({ id: task.id, status: "open" }).update({
271
241
  status: "processing",
272
242
  last_heartbeat_at: this.db.fn.now(),
273
- // Retain secrets only when recovery is enabled (globally or via the
274
- // legacy per-template strategy) so recovered tasks can resume.
275
- // Otherwise clear them on claim to preserve the default security
276
- // lifecycle.
277
- secrets: this.recoverTasksEnabled || this.isRecoverableTask(spec) ? task.secrets : null
243
+ // remove the secrets for non-recoverable tasks when moving to processing state.
244
+ secrets: this.isRecoverableTask(spec) ? task.secrets : null
278
245
  });
279
246
  if (updateCount < 1) {
280
247
  return void 0;
@@ -307,7 +274,7 @@ class DatabaseTaskStore {
307
274
  async listStaleTasks(options) {
308
275
  const { timeoutS } = options;
309
276
  const heartbeatInterval = dbUtil.intervalFromNowTill(timeoutS, this.db);
310
- const rawRows = await this.db("tasks").where("status", "processing").andWhere("last_heartbeat_at", "<=", heartbeatInterval).select(["id", "spec"]);
277
+ const rawRows = await this.db("tasks").where("status", "processing").andWhere("last_heartbeat_at", "<=", heartbeatInterval);
311
278
  const tasks = rawRows.map((row) => ({
312
279
  recovery: JSON.parse(row.spec).EXPERIMENTAL_recovery,
313
280
  taskId: row.id
@@ -327,14 +294,7 @@ class DatabaseTaskStore {
327
294
  await this.db.transaction(async (tx) => {
328
295
  const [task] = await tx("tasks").where({
329
296
  id: taskId
330
- }).limit(1).select([
331
- "id",
332
- "status",
333
- "state",
334
- "last_heartbeat_at",
335
- "created_at",
336
- "created_by"
337
- ]);
297
+ }).limit(1).select();
338
298
  const updateTask = async (criteria) => {
339
299
  const updateCount = await tx("tasks").where(criteria).update({
340
300
  status,
@@ -407,7 +367,7 @@ class DatabaseTaskStore {
407
367
  }
408
368
  }
409
369
  async listEvents(options) {
410
- const { taskId, after, isTaskRecoverable } = options;
370
+ const { isTaskRecoverable, taskId, after } = options;
411
371
  const rawEvents = await this.db("task_events").where({
412
372
  task_id: taskId
413
373
  }).andWhere((builder) => {
@@ -462,18 +422,34 @@ class DatabaseTaskStore {
462
422
  }
463
423
  });
464
424
  }
425
+ async rehydrateWorkspace(options) {
426
+ const [result] = await this.db("tasks").where({ id: options.taskId }).select("workspace");
427
+ await alpha.restoreWorkspace({
428
+ path: options.targetPath,
429
+ buffer: result.workspace
430
+ });
431
+ }
432
+ async cleanWorkspace({ taskId }) {
433
+ await this.db("tasks").where({ id: taskId }).update({
434
+ workspace: null
435
+ });
436
+ }
437
+ async serializeWorkspace(options) {
438
+ if (options.path) {
439
+ const workspace = (await alpha.serializeWorkspace(options)).contents;
440
+ await this.db("tasks").where({ id: options.taskId }).update({
441
+ workspace
442
+ });
443
+ }
444
+ }
465
445
  async cancelTask(options) {
466
446
  const { taskId, body } = options;
467
447
  const serializedBody = JSON.stringify(body);
468
- const ret = await this.db.transaction(async (tx) => {
469
- await tx("tasks").where({ id: taskId }).update({ secrets: null });
470
- const [event] = await tx("task_events").insert({
471
- task_id: taskId,
472
- event_type: "cancelled",
473
- body: serializedBody
474
- }).returning("id");
475
- return event;
476
- });
448
+ const [ret] = await this.db("task_events").insert({
449
+ task_id: taskId,
450
+ event_type: "cancelled",
451
+ body: serializedBody
452
+ }).returning("id");
477
453
  this.events?.publish({
478
454
  topic: "scaffolder.task",
479
455
  eventPayload: {
@@ -487,25 +463,24 @@ class DatabaseTaskStore {
487
463
  async retryTask(options) {
488
464
  const { secrets, taskId } = options;
489
465
  await this.db.transaction(async (tx) => {
490
- const result = await tx("tasks").where("id", taskId).update(
491
- {
492
- ...secrets && { secrets: JSON.stringify(secrets) },
493
- status: "open",
494
- last_heartbeat_at: this.db.fn.now()
495
- },
496
- ["id", "spec"]
497
- );
498
- for (const { id, spec } of result) {
499
- const taskSpec = JSON.parse(spec);
500
- await tx("task_events").where("task_id", id).andWhere((q) => q.whereIn("event_type", ["cancelled", "completion"])).del();
501
- await tx("task_events").insert({
502
- task_id: id,
503
- event_type: "recovered",
504
- body: JSON.stringify({
505
- recoverStrategy: taskSpec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? "none"
506
- })
507
- });
466
+ const updateCount = await tx("tasks").where("id", taskId).whereIn("status", ["cancelled", "completed", "failed", "skipped"]).update({
467
+ ...secrets && { secrets: JSON.stringify(secrets) },
468
+ status: "open",
469
+ last_heartbeat_at: this.db.fn.now()
470
+ });
471
+ if (Number(updateCount) !== 1) {
472
+ throw new errors.ConflictError(`Task with taskId ${taskId} cannot be retried`);
508
473
  }
474
+ const [task] = await tx("tasks").where("id", taskId).select("id", "spec");
475
+ const taskSpec = JSON.parse(task.spec);
476
+ await tx("task_events").where("task_id", task.id).andWhere((q) => q.whereIn("event_type", ["cancelled", "completion"])).del();
477
+ await tx("task_events").insert({
478
+ task_id: task.id,
479
+ event_type: "recovered",
480
+ body: JSON.stringify({
481
+ recoverStrategy: taskSpec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? "none"
482
+ })
483
+ });
509
484
  });
510
485
  }
511
486
  async recoverTasks(options) {
@@ -1 +1 @@
1
- {"version":3,"file":"DatabaseTaskStore.cjs.js","sources":["../../../src/scaffolder/tasks/DatabaseTaskStore.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 {\n DatabaseService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { randomUUID as uuid } from 'node:crypto';\nimport {\n TaskStore,\n TaskStoreCreateTaskOptions,\n TaskStoreCreateTaskResult,\n TaskStoreEmitOptions,\n TaskStoreListEventsOptions,\n TaskStoreRecoverTaskOptions,\n TaskStoreShutDownTaskOptions,\n} from './types';\nimport {\n SerializedTask,\n SerializedTaskEvent,\n TaskEventType,\n TaskFilter,\n TaskSecrets,\n TaskStatus,\n} from '@backstage/plugin-scaffolder-node';\nimport { DateTime, Duration } from 'luxon';\nimport { TaskRecovery, TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { trimEventsTillLastRecovery } from './taskRecoveryHelper';\nimport { intervalFromNowTill } from './dbUtil';\nimport { flattenParams } from '../../service/helpers';\nimport { EventsService } from '@backstage/plugin-events-node';\nimport { PermissionCriteria } from '@backstage/plugin-permission-common';\nimport {\n isAndCriteria,\n isNotCriteria,\n isOrCriteria,\n} from '@backstage/plugin-permission-node';\nimport { TaskFilters } from '@backstage/plugin-scaffolder-node';\nimport { compact } from 'lodash';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage/plugin-scaffolder-backend',\n 'migrations',\n);\n\nexport type RawDbTaskRow = {\n id: string;\n spec: string;\n status: TaskStatus;\n state?: string;\n last_heartbeat_at?: string;\n created_at: string;\n created_by: string | null;\n secrets?: string | null;\n workspace?: Buffer;\n};\n\nexport type RawDbTaskEventRow = {\n id: number;\n task_id: string;\n body: string;\n event_type: TaskEventType;\n created_at: string;\n};\n\n/**\n * DatabaseTaskStore\n */\nexport type DatabaseTaskStoreOptions = {\n database: DatabaseService | Knex;\n events?: EventsService;\n /**\n * Whether automatic task recovery is enabled. When enabled, task secrets are\n * retained until the task reaches a terminal state so that a recovered task\n * can resume. When disabled (the default), secrets are cleared as soon as the\n * task is claimed, preserving the original security lifecycle.\n */\n recoverTasksEnabled?: boolean;\n};\n\n/**\n * Type guard to help DatabaseTaskStore understand when database is DatabaseService vs. when database is a Knex instance.\n * */\nfunction isDatabaseService(\n opt: DatabaseService | Knex,\n): opt is DatabaseService {\n return (opt as DatabaseService).getClient !== undefined;\n}\n\nconst parseSqlDateToIsoString = <T>(input: T): T | string => {\n if (typeof input === 'string') {\n const parsed = DateTime.fromSQL(input, { zone: 'UTC' });\n if (!parsed.isValid) {\n throw new Error(\n `Failed to parse database timestamp '${input}', ${parsed.invalidReason}: ${parsed.invalidExplanation}`,\n );\n }\n return parsed.toISO()!;\n }\n\n return input;\n};\n\n/**\n * DatabaseTaskStore\n */\nexport class DatabaseTaskStore implements TaskStore {\n private readonly db: Knex;\n private readonly events?: EventsService;\n private readonly recoverTasksEnabled: boolean;\n\n static async create(\n options: DatabaseTaskStoreOptions,\n ): Promise<DatabaseTaskStore> {\n const { database } = options;\n const client = await this.getClient(database);\n\n await this.runMigrations(database, client);\n\n return new DatabaseTaskStore(\n client,\n options.events,\n options.recoverTasksEnabled ?? false,\n );\n }\n\n private isRecoverableTask(spec: TaskSpec): boolean {\n return ['startOver'].includes(\n spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? 'none',\n );\n }\n\n private parseSpec({ spec, id }: { spec: string; id: string }): TaskSpec {\n try {\n return JSON.parse(spec);\n } catch (error) {\n throw new Error(`Failed to parse spec of task '${id}', ${error}`);\n }\n }\n\n private parseTaskSecrets(taskRow: RawDbTaskRow): TaskSecrets | undefined {\n try {\n return taskRow.secrets ? JSON.parse(taskRow.secrets) : undefined;\n } catch (error) {\n throw new Error(\n `Failed to parse secrets of task '${taskRow.id}', ${error}`,\n );\n }\n }\n\n private static async getClient(\n database: DatabaseService | Knex,\n ): Promise<Knex> {\n if (isDatabaseService(database)) {\n return database.getClient();\n }\n\n return database;\n }\n\n private static async runMigrations(\n database: DatabaseService | Knex,\n client: Knex,\n ): Promise<void> {\n if (!isDatabaseService(database)) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n\n return;\n }\n\n if (!database.migrations?.skip) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n }\n\n private constructor(\n client: Knex,\n events: EventsService | undefined,\n recoverTasksEnabled: boolean,\n ) {\n this.db = client;\n this.events = events;\n this.recoverTasksEnabled = recoverTasksEnabled;\n }\n\n private getState(task: Pick<RawDbTaskRow, 'id' | 'state'>) {\n try {\n return task.state ? JSON.parse(task.state).state : undefined;\n } catch (error) {\n throw new Error(\n `Failed to parse state of the task '${task.id}', ${error}`,\n );\n }\n }\n\n private isTaskFilter(filter: any): filter is TaskFilter {\n return filter.hasOwnProperty('key');\n }\n\n private parseFilter(\n filter: PermissionCriteria<TaskFilters>,\n query: Knex.QueryBuilder,\n db: Knex,\n negate: boolean = false,\n ): Knex.QueryBuilder {\n if (isNotCriteria(filter)) {\n return this.parseFilter(filter.not, query, db, !negate);\n }\n\n if (this.isTaskFilter(filter)) {\n const values: string[] = compact(filter.values) ?? [];\n if (negate) {\n query.whereNotIn(filter.key, values);\n } else {\n query.whereIn(filter.key, values);\n }\n\n return query;\n }\n\n return query[negate ? 'andWhereNot' : 'andWhere'](subQuery => {\n if (isOrCriteria(filter)) {\n for (const subFilter of filter.anyOf ?? []) {\n subQuery.orWhere(subQueryInner =>\n this.parseFilter(subFilter, subQueryInner, db, false),\n );\n }\n } else if (isAndCriteria(filter)) {\n for (const subFilter of filter.allOf ?? []) {\n subQuery.andWhere(subQueryInner =>\n this.parseFilter(subFilter, subQueryInner, db, false),\n );\n }\n }\n });\n }\n\n async list(options: {\n createdBy?: string;\n status?: TaskStatus;\n filters?: {\n createdBy?: string | string[];\n status?: TaskStatus | TaskStatus[];\n };\n pagination?: {\n limit?: number;\n offset?: number;\n };\n order?: { order: 'asc' | 'desc'; field: string }[];\n permissionFilters?: PermissionCriteria<TaskFilters>;\n }): Promise<{ tasks: SerializedTask[]; totalTasks?: number }> {\n const { createdBy, status, pagination, order, filters, permissionFilters } =\n options ?? {};\n const queryBuilder = this.db<RawDbTaskRow & { count: number }>('tasks');\n\n const createdByValues = flattenParams<string>(\n createdBy,\n filters?.createdBy,\n );\n\n const combinedPermissionFilters:\n | PermissionCriteria<TaskFilters>\n | undefined =\n createdByValues.length > 0\n ? {\n allOf: [\n { key: 'created_by', values: createdByValues },\n ...(permissionFilters ? [permissionFilters] : []),\n ],\n }\n : permissionFilters;\n\n if (combinedPermissionFilters) {\n this.parseFilter(combinedPermissionFilters, queryBuilder, this.db);\n }\n\n if (status || filters?.status) {\n const arr: TaskStatus[] = flattenParams<TaskStatus>(\n status,\n filters?.status,\n );\n queryBuilder.whereIn('status', [...new Set(arr)]);\n }\n\n const countQuery = queryBuilder.clone();\n countQuery.count('tasks.id', { as: 'count' });\n\n if (order) {\n order.forEach(f => {\n queryBuilder.orderBy(f.field, f.order);\n });\n } else {\n queryBuilder.orderBy('created_at', 'desc');\n }\n\n if (pagination?.limit !== undefined) {\n queryBuilder.limit(pagination.limit);\n }\n\n if (pagination?.offset !== undefined) {\n queryBuilder.offset(pagination.offset);\n }\n\n const [results, [{ count }]] = await Promise.all([\n queryBuilder.select([\n 'id',\n 'spec',\n 'status',\n 'created_by',\n 'last_heartbeat_at',\n 'created_at',\n ]),\n countQuery,\n ]);\n\n const tasks = results.map(result => ({\n id: result.id,\n spec: JSON.parse(result.spec),\n status: result.status,\n createdBy: result.created_by ?? undefined,\n lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at),\n createdAt: parseSqlDateToIsoString(result.created_at),\n }));\n\n // `count` is coerced to a number because knex returns the result of a\n // `COUNT(*)` aggregate as a string on PostgreSQL (the underlying column is\n // a bigint), whereas it is a number on better-sqlite3. Without this the\n // `totalTasks` value would be a string in production, which breaks\n // consumers that expect a number (e.g. the `list-scaffolder-tasks` action\n // whose output schema declares `totalTasks: z.number()`).\n const totalTasks = Number(count);\n if (!Number.isSafeInteger(totalTasks)) {\n // A bigint count above Number.MAX_SAFE_INTEGER would silently lose\n // precision when coerced, so fail loudly rather than report a wrong total.\n throw new Error(\n `Task count '${count}' exceeds the safe integer range and cannot be represented accurately as 'totalTasks'`,\n );\n }\n\n return { tasks, totalTasks };\n }\n\n async getTask(taskId: string): Promise<SerializedTask> {\n const [result] = await this.db<RawDbTaskRow>('tasks')\n .where({ id: taskId })\n .select([\n 'id',\n 'spec',\n 'status',\n 'state',\n 'last_heartbeat_at',\n 'created_at',\n 'created_by',\n 'secrets',\n ]);\n if (!result) {\n throw new NotFoundError(`No task with id '${taskId}' found`);\n }\n try {\n return this.parseTaskRow(result);\n } catch (error) {\n throw new Error(`Failed to parse spec of task '${taskId}', ${error}`);\n }\n }\n\n private parseTaskRow(result: RawDbTaskRow): SerializedTask {\n const spec = JSON.parse(result.spec);\n const secrets = result.secrets ? JSON.parse(result.secrets) : undefined;\n const state = this.getState(result);\n\n return {\n id: result.id,\n spec,\n status: result.status,\n lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at),\n createdAt: parseSqlDateToIsoString(result.created_at),\n createdBy: result.created_by ?? undefined,\n secrets,\n state,\n };\n }\n\n async createTask(\n options: TaskStoreCreateTaskOptions,\n ): Promise<TaskStoreCreateTaskResult> {\n const taskId = uuid();\n await this.db<RawDbTaskRow>('tasks').insert({\n id: taskId,\n spec: JSON.stringify(options.spec),\n secrets: options.secrets ? JSON.stringify(options.secrets) : undefined,\n created_by: options.createdBy ?? null,\n status: 'open',\n });\n\n this.events?.publish({\n topic: 'scaffolder.task',\n eventPayload: {\n id: taskId,\n spec: options.spec,\n createdBy: options.createdBy,\n status: 'open',\n },\n });\n\n return { taskId };\n }\n\n async claimTask(): Promise<SerializedTask | undefined> {\n return this.db.transaction(async tx => {\n const [task] = await tx<RawDbTaskRow>('tasks')\n .where({\n status: 'open',\n })\n .limit(1)\n .select([\n 'id',\n 'spec',\n 'status',\n 'state',\n 'last_heartbeat_at',\n 'created_at',\n 'created_by',\n 'secrets',\n ]);\n\n if (!task) {\n return undefined;\n }\n\n const spec = this.parseSpec(task);\n\n const updateCount = await tx<RawDbTaskRow>('tasks')\n .where({ id: task.id, status: 'open' })\n .update({\n status: 'processing',\n last_heartbeat_at: this.db.fn.now(),\n // Retain secrets only when recovery is enabled (globally or via the\n // legacy per-template strategy) so recovered tasks can resume.\n // Otherwise clear them on claim to preserve the default security\n // lifecycle.\n secrets:\n this.recoverTasksEnabled || this.isRecoverableTask(spec)\n ? task.secrets\n : null,\n });\n\n if (updateCount < 1) {\n return undefined;\n }\n\n const ret: SerializedTask = {\n id: task.id,\n spec,\n status: 'processing',\n lastHeartbeatAt: task.last_heartbeat_at,\n createdAt: task.created_at,\n createdBy: task.created_by ?? undefined,\n state: this.getState(task),\n };\n\n this.events?.publish({\n topic: 'scaffolder.task',\n eventPayload: ret,\n });\n\n const secrets = this.parseTaskSecrets(task);\n return { ...ret, secrets };\n });\n }\n\n async heartbeatTask(taskId: string): Promise<void> {\n const updateCount = await this.db<RawDbTaskRow>('tasks')\n .where({ id: taskId, status: 'processing' })\n .update({\n last_heartbeat_at: this.db.fn.now(),\n });\n if (updateCount === 0) {\n throw new ConflictError(`No running task with taskId ${taskId} found`);\n }\n }\n\n async listStaleTasks(options: { timeoutS: number }): Promise<{\n tasks: { taskId: string; recovery?: TaskRecovery }[];\n }> {\n const { timeoutS } = options;\n const heartbeatInterval = intervalFromNowTill(timeoutS, this.db);\n const rawRows = await this.db<RawDbTaskRow>('tasks')\n .where('status', 'processing')\n .andWhere('last_heartbeat_at', '<=', heartbeatInterval)\n .select(['id', 'spec']);\n const tasks = rawRows.map(row => ({\n recovery: (JSON.parse(row.spec) as TaskSpec).EXPERIMENTAL_recovery,\n taskId: row.id,\n }));\n return { tasks };\n }\n\n async completeTask(options: {\n taskId: string;\n status: TaskStatus;\n eventBody: JsonObject;\n }): Promise<void> {\n const { taskId, status, eventBody } = options;\n\n let oldStatus: TaskStatus;\n if (['failed', 'completed', 'cancelled'].includes(status)) {\n oldStatus = 'processing';\n } else {\n throw new Error(\n `Invalid status update of run '${taskId}' to status '${status}'`,\n );\n }\n\n await this.db.transaction(async tx => {\n const [task] = await tx<RawDbTaskRow>('tasks')\n .where({\n id: taskId,\n })\n .limit(1)\n .select([\n 'id',\n 'status',\n 'state',\n 'last_heartbeat_at',\n 'created_at',\n 'created_by',\n ]);\n\n const updateTask = async (criteria: {\n id: string;\n status?: TaskStatus;\n }) => {\n const updateCount = await tx<RawDbTaskRow>('tasks')\n .where(criteria)\n .update({\n status,\n secrets: null,\n });\n\n if (updateCount !== 1) {\n throw new ConflictError(\n `Failed to update status to '${status}' for taskId ${taskId}`,\n );\n }\n\n this.events?.publish({\n topic: 'scaffolder.task',\n eventPayload: {\n id: taskId,\n status: status,\n lastHeartbeatAt: task.last_heartbeat_at,\n createdAt: task.created_at,\n createdBy: task.created_by,\n state: this.getState(task),\n },\n });\n\n await tx<RawDbTaskEventRow>('task_events')\n .insert({\n task_id: taskId,\n event_type: 'completion',\n body: JSON.stringify(eventBody),\n })\n .returning('id');\n };\n\n if (status === 'cancelled') {\n await updateTask({\n id: taskId,\n });\n return;\n }\n\n if (task.status === 'cancelled') {\n return;\n }\n\n if (!task) {\n throw new Error(`No task with taskId ${taskId} found`);\n }\n if (task.status !== oldStatus) {\n throw new ConflictError(\n `Refusing to update status of run '${taskId}' to status '${status}' ` +\n `as it is currently '${task.status}', expected '${oldStatus}'`,\n );\n }\n\n await updateTask({\n id: taskId,\n status: oldStatus,\n });\n });\n }\n\n async emitLogEvent(\n options: TaskStoreEmitOptions<{ message: string } & JsonObject>,\n ): Promise<void> {\n const { taskId, body } = options;\n const serializedBody = JSON.stringify(body);\n await this.db<RawDbTaskEventRow>('task_events')\n .insert({\n task_id: taskId,\n event_type: 'log',\n body: serializedBody,\n })\n .returning('id');\n }\n\n async getTaskState({ taskId }: { taskId: string }): Promise<\n | {\n state: JsonObject;\n }\n | undefined\n > {\n const [result] = await this.db<RawDbTaskRow>('tasks')\n .where({ id: taskId })\n .select('state');\n return result.state ? JSON.parse(result.state) : undefined;\n }\n\n async saveTaskState(options: {\n taskId: string;\n state?: JsonObject;\n }): Promise<void> {\n if (options.state) {\n const serializedState = JSON.stringify({ state: options.state });\n await this.db<RawDbTaskRow>('tasks')\n .where({ id: options.taskId })\n .update({\n state: serializedState,\n });\n }\n }\n\n async listEvents(\n options: TaskStoreListEventsOptions,\n ): Promise<{ events: SerializedTaskEvent[] }> {\n const { taskId, after, isTaskRecoverable } = options;\n const rawEvents = await this.db<RawDbTaskEventRow>('task_events')\n .where({\n task_id: taskId,\n })\n .andWhere(builder => {\n if (typeof after === 'number') {\n builder.where('id', '>', after).orWhere('event_type', 'completion');\n }\n })\n .orderBy('id')\n .select();\n\n const events = rawEvents.map(event => {\n try {\n const body = JSON.parse(event.body) as SerializedTaskEvent['body'];\n return {\n id: Number(event.id),\n isTaskRecoverable,\n taskId,\n body,\n type: event.event_type,\n createdAt: parseSqlDateToIsoString(event.created_at),\n };\n } catch (error) {\n throw new Error(\n `Failed to parse event body from event taskId=${taskId} id=${event.id}, ${error}`,\n );\n }\n });\n\n return trimEventsTillLastRecovery(events);\n }\n\n async shutdownTask(options: TaskStoreShutDownTaskOptions): Promise<void> {\n const { taskId } = options;\n const message = `This task was marked as stale as it exceeded its timeout`;\n\n const statusStepEvents = (await this.listEvents({ taskId })).events.filter(\n ({ body }) => body?.stepId,\n );\n\n const completedSteps = statusStepEvents\n .filter(\n ({ body: { status } }) => status === 'failed' || status === 'completed',\n )\n .map(step => step.body.stepId);\n\n const hungProcessingSteps = statusStepEvents\n .filter(({ body: { status } }) => status === 'processing')\n .map(event => event.body.stepId)\n .filter(step => !completedSteps.includes(step));\n\n for (const step of hungProcessingSteps) {\n await this.emitLogEvent({\n taskId,\n body: {\n message,\n stepId: step,\n status: 'failed',\n },\n });\n }\n\n await this.completeTask({\n taskId,\n status: 'failed',\n eventBody: {\n message,\n },\n });\n }\n\n async cancelTask(\n options: TaskStoreEmitOptions<{ message: string } & JsonObject>,\n ): Promise<void> {\n const { taskId, body } = options;\n const serializedBody = JSON.stringify(body);\n const ret = await this.db.transaction(async tx => {\n await tx<RawDbTaskRow>('tasks')\n .where({ id: taskId })\n .update({ secrets: null });\n\n const [event] = await tx<RawDbTaskEventRow>('task_events')\n .insert({\n task_id: taskId,\n event_type: 'cancelled',\n body: serializedBody,\n })\n .returning('id');\n\n return event;\n });\n\n this.events?.publish({\n topic: 'scaffolder.task',\n eventPayload: {\n id: ret.id,\n taskId,\n status: 'cancelled',\n body,\n },\n });\n }\n\n async retryTask(options: {\n secrets?: TaskSecrets;\n taskId: string;\n }): Promise<void> {\n const { secrets, taskId } = options;\n\n await this.db.transaction(async tx => {\n const result = await tx<RawDbTaskRow>('tasks')\n .where('id', taskId)\n .update(\n {\n ...(secrets && { secrets: JSON.stringify(secrets) }),\n status: 'open',\n last_heartbeat_at: this.db.fn.now(),\n },\n ['id', 'spec'],\n );\n\n for (const { id, spec } of result) {\n const taskSpec = JSON.parse(spec as string) as TaskSpec;\n\n /**\n * Once task is picked up, all event types are replayed.\n * We have to remove cancelled or completion event_type as these are as actions for frontend to perform.\n * In contrary, we send 'recovered' event_type to reset the state on the frontend side.\n *\n */\n await tx<RawDbTaskEventRow>('task_events')\n .where('task_id', id)\n .andWhere(q => q.whereIn('event_type', ['cancelled', 'completion']))\n .del();\n\n await tx<RawDbTaskEventRow>('task_events').insert({\n task_id: id,\n event_type: 'recovered',\n body: JSON.stringify({\n recoverStrategy:\n taskSpec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? 'none',\n }),\n });\n }\n });\n }\n\n async recoverTasks(\n options: TaskStoreRecoverTaskOptions,\n ): Promise<{ ids: string[] }> {\n const taskIdsToRecover: string[] = [];\n const timeoutS = Duration.fromObject(options.timeout).as('seconds');\n\n await this.db.transaction(async tx => {\n const heartbeatInterval = intervalFromNowTill(timeoutS, this.db);\n\n const result = await tx<RawDbTaskRow>('tasks')\n .where('status', 'processing')\n .andWhere('last_heartbeat_at', '<=', heartbeatInterval)\n .update(\n {\n status: 'open',\n last_heartbeat_at: this.db.fn.now(),\n },\n ['id', 'spec'],\n );\n\n taskIdsToRecover.push(...result.map(i => i.id));\n\n for (const { id, spec } of result) {\n const taskSpec = JSON.parse(spec as string) as TaskSpec;\n const event = {\n recoverStrategy:\n taskSpec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? 'none',\n };\n const [ret] = await tx<RawDbTaskEventRow>('task_events')\n .insert({\n task_id: id,\n event_type: 'recovered',\n body: JSON.stringify(event),\n })\n .returning('id');\n\n this.events?.publish({\n topic: 'scaffolder.task',\n eventPayload: {\n id: ret.id,\n taskId: id,\n status: 'recovered',\n body: event,\n },\n });\n }\n });\n\n return { ids: taskIdsToRecover };\n }\n}\n"],"names":["resolvePackagePath","DateTime","isNotCriteria","compact","isOrCriteria","isAndCriteria","flattenParams","NotFoundError","uuid","ConflictError","intervalFromNowTill","trimEventsTillLastRecovery","Duration"],"mappings":"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"}
1
+ {"version":3,"file":"DatabaseTaskStore.cjs.js","sources":["../../../src/scaffolder/tasks/DatabaseTaskStore.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 {\n DatabaseService,\n resolvePackagePath,\n} from '@backstage/backend-plugin-api';\nimport { ConflictError, NotFoundError } from '@backstage/errors';\nimport { Knex } from 'knex';\nimport { randomUUID as uuid } from 'node:crypto';\nimport {\n TaskStore,\n TaskStoreCreateTaskOptions,\n TaskStoreCreateTaskResult,\n TaskStoreEmitOptions,\n TaskStoreListEventsOptions,\n TaskStoreRecoverTaskOptions,\n TaskStoreShutDownTaskOptions,\n} from './types';\nimport {\n SerializedTask,\n SerializedTaskEvent,\n TaskEventType,\n TaskFilter,\n TaskSecrets,\n TaskStatus,\n} from '@backstage/plugin-scaffolder-node';\nimport { DateTime, Duration } from 'luxon';\nimport { TaskRecovery, TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport { trimEventsTillLastRecovery } from './taskRecoveryHelper';\nimport { intervalFromNowTill } from './dbUtil';\nimport {\n restoreWorkspace,\n serializeWorkspace,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport { flattenParams } from '../../service/helpers';\nimport { EventsService } from '@backstage/plugin-events-node';\nimport { PermissionCriteria } from '@backstage/plugin-permission-common';\nimport {\n isAndCriteria,\n isNotCriteria,\n isOrCriteria,\n} from '@backstage/plugin-permission-node';\nimport { TaskFilters } from '@backstage/plugin-scaffolder-node';\nimport { compact } from 'lodash';\n\nconst migrationsDir = resolvePackagePath(\n '@backstage/plugin-scaffolder-backend',\n 'migrations',\n);\n\nexport type RawDbTaskRow = {\n id: string;\n spec: string;\n status: TaskStatus;\n state?: string;\n last_heartbeat_at?: string;\n created_at: string;\n created_by: string | null;\n secrets?: string | null;\n workspace?: Buffer;\n};\n\nexport type RawDbTaskEventRow = {\n id: number;\n task_id: string;\n body: string;\n event_type: TaskEventType;\n created_at: string;\n};\n\n/**\n * DatabaseTaskStore\n */\nexport type DatabaseTaskStoreOptions = {\n database: DatabaseService | Knex;\n events?: EventsService;\n};\n\n/**\n * Type guard to help DatabaseTaskStore understand when database is DatabaseService vs. when database is a Knex instance.\n * */\nfunction isDatabaseService(\n opt: DatabaseService | Knex,\n): opt is DatabaseService {\n return (opt as DatabaseService).getClient !== undefined;\n}\n\nconst parseSqlDateToIsoString = <T>(input: T): T | string => {\n if (typeof input === 'string') {\n const parsed = DateTime.fromSQL(input, { zone: 'UTC' });\n if (!parsed.isValid) {\n throw new Error(\n `Failed to parse database timestamp '${input}', ${parsed.invalidReason}: ${parsed.invalidExplanation}`,\n );\n }\n return parsed.toISO()!;\n }\n\n return input;\n};\n\n/**\n * DatabaseTaskStore\n */\nexport class DatabaseTaskStore implements TaskStore {\n private readonly db: Knex;\n private readonly events?: EventsService;\n\n static async create(\n options: DatabaseTaskStoreOptions,\n ): Promise<DatabaseTaskStore> {\n const { database } = options;\n const client = await this.getClient(database);\n\n await this.runMigrations(database, client);\n\n return new DatabaseTaskStore(client, options.events);\n }\n\n private isRecoverableTask(spec: TaskSpec): boolean {\n return ['startOver'].includes(\n spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? 'none',\n );\n }\n\n private parseSpec({ spec, id }: { spec: string; id: string }): TaskSpec {\n try {\n return JSON.parse(spec);\n } catch (error) {\n throw new Error(`Failed to parse spec of task '${id}', ${error}`);\n }\n }\n\n private parseTaskSecrets(taskRow: RawDbTaskRow): TaskSecrets | undefined {\n try {\n return taskRow.secrets ? JSON.parse(taskRow.secrets) : undefined;\n } catch (error) {\n throw new Error(\n `Failed to parse secrets of task '${taskRow.id}', ${error}`,\n );\n }\n }\n\n private static async getClient(\n database: DatabaseService | Knex,\n ): Promise<Knex> {\n if (isDatabaseService(database)) {\n return database.getClient();\n }\n\n return database;\n }\n\n private static async runMigrations(\n database: DatabaseService | Knex,\n client: Knex,\n ): Promise<void> {\n if (!isDatabaseService(database)) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n\n return;\n }\n\n if (!database.migrations?.skip) {\n await client.migrate.latest({\n directory: migrationsDir,\n });\n }\n }\n\n private constructor(client: Knex, events?: EventsService) {\n this.db = client;\n this.events = events;\n }\n\n private getState(task: RawDbTaskRow) {\n try {\n return task.state ? JSON.parse(task.state).state : undefined;\n } catch (error) {\n throw new Error(\n `Failed to parse state of the task '${task.id}', ${error}`,\n );\n }\n }\n\n private isTaskFilter(filter: any): filter is TaskFilter {\n return filter.hasOwnProperty('key');\n }\n\n private parseFilter(\n filter: PermissionCriteria<TaskFilters>,\n query: Knex.QueryBuilder,\n db: Knex,\n negate: boolean = false,\n ): Knex.QueryBuilder {\n if (isNotCriteria(filter)) {\n return this.parseFilter(filter.not, query, db, !negate);\n }\n\n if (this.isTaskFilter(filter)) {\n const values: string[] = compact(filter.values) ?? [];\n if (negate) {\n query.whereNotIn(filter.key, values);\n } else {\n query.whereIn(filter.key, values);\n }\n\n return query;\n }\n\n return query[negate ? 'andWhereNot' : 'andWhere'](subQuery => {\n if (isOrCriteria(filter)) {\n for (const subFilter of filter.anyOf ?? []) {\n subQuery.orWhere(subQueryInner =>\n this.parseFilter(subFilter, subQueryInner, db, false),\n );\n }\n } else if (isAndCriteria(filter)) {\n for (const subFilter of filter.allOf ?? []) {\n subQuery.andWhere(subQueryInner =>\n this.parseFilter(subFilter, subQueryInner, db, false),\n );\n }\n }\n });\n }\n\n async list(options: {\n createdBy?: string;\n status?: TaskStatus;\n filters?: {\n createdBy?: string | string[];\n status?: TaskStatus | TaskStatus[];\n };\n pagination?: {\n limit?: number;\n offset?: number;\n };\n order?: { order: 'asc' | 'desc'; field: string }[];\n permissionFilters?: PermissionCriteria<TaskFilters>;\n }): Promise<{ tasks: SerializedTask[]; totalTasks?: number }> {\n const { createdBy, status, pagination, order, filters, permissionFilters } =\n options ?? {};\n const queryBuilder = this.db<RawDbTaskRow & { count: number }>('tasks');\n\n const createdByValues = flattenParams<string>(\n createdBy,\n filters?.createdBy,\n );\n\n const combinedPermissionFilters:\n | PermissionCriteria<TaskFilters>\n | undefined =\n createdByValues.length > 0\n ? {\n allOf: [\n { key: 'created_by', values: createdByValues },\n ...(permissionFilters ? [permissionFilters] : []),\n ],\n }\n : permissionFilters;\n\n if (combinedPermissionFilters) {\n this.parseFilter(combinedPermissionFilters, queryBuilder, this.db);\n }\n\n if (status || filters?.status) {\n const arr: TaskStatus[] = flattenParams<TaskStatus>(\n status,\n filters?.status,\n );\n queryBuilder.whereIn('status', [...new Set(arr)]);\n }\n\n const countQuery = queryBuilder.clone();\n countQuery.count('tasks.id', { as: 'count' });\n\n if (order) {\n order.forEach(f => {\n queryBuilder.orderBy(f.field, f.order);\n });\n } else {\n queryBuilder.orderBy('created_at', 'desc');\n }\n\n if (pagination?.limit !== undefined) {\n queryBuilder.limit(pagination.limit);\n }\n\n if (pagination?.offset !== undefined) {\n queryBuilder.offset(pagination.offset);\n }\n\n const [results, [{ count }]] = await Promise.all([\n queryBuilder.select(),\n countQuery,\n ]);\n\n const tasks = results.map(result => ({\n id: result.id,\n spec: JSON.parse(result.spec),\n status: result.status,\n createdBy: result.created_by ?? undefined,\n lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at),\n createdAt: parseSqlDateToIsoString(result.created_at),\n }));\n\n // `count` is coerced to a number because knex returns the result of a\n // `COUNT(*)` aggregate as a string on PostgreSQL (the underlying column is\n // a bigint), whereas it is a number on better-sqlite3. Without this the\n // `totalTasks` value would be a string in production, which breaks\n // consumers that expect a number (e.g. the `list-scaffolder-tasks` action\n // whose output schema declares `totalTasks: z.number()`).\n const totalTasks = Number(count);\n if (!Number.isSafeInteger(totalTasks)) {\n // A bigint count above Number.MAX_SAFE_INTEGER would silently lose\n // precision when coerced, so fail loudly rather than report a wrong total.\n throw new Error(\n `Task count '${count}' exceeds the safe integer range and cannot be represented accurately as 'totalTasks'`,\n );\n }\n\n return { tasks, totalTasks };\n }\n\n async getTask(taskId: string): Promise<SerializedTask> {\n const [result] = await this.db<RawDbTaskRow>('tasks')\n .where({ id: taskId })\n .select();\n if (!result) {\n throw new NotFoundError(`No task with id '${taskId}' found`);\n }\n try {\n return this.parseTaskRow(result);\n } catch (error) {\n throw new Error(`Failed to parse spec of task '${taskId}', ${error}`);\n }\n }\n\n private parseTaskRow(result: RawDbTaskRow): SerializedTask {\n const spec = JSON.parse(result.spec);\n const secrets = result.secrets ? JSON.parse(result.secrets) : undefined;\n const state = this.getState(result);\n\n return {\n id: result.id,\n spec,\n status: result.status,\n lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at),\n createdAt: parseSqlDateToIsoString(result.created_at),\n createdBy: result.created_by ?? undefined,\n secrets,\n state,\n };\n }\n\n async createTask(\n options: TaskStoreCreateTaskOptions,\n ): Promise<TaskStoreCreateTaskResult> {\n const taskId = uuid();\n await this.db<RawDbTaskRow>('tasks').insert({\n id: taskId,\n spec: JSON.stringify(options.spec),\n secrets: options.secrets ? JSON.stringify(options.secrets) : undefined,\n created_by: options.createdBy ?? null,\n status: 'open',\n });\n\n this.events?.publish({\n topic: 'scaffolder.task',\n eventPayload: {\n id: taskId,\n spec: options.spec,\n createdBy: options.createdBy,\n status: 'open',\n },\n });\n\n return { taskId };\n }\n\n async claimTask(): Promise<SerializedTask | undefined> {\n return this.db.transaction(async tx => {\n const [task] = await tx<RawDbTaskRow>('tasks')\n .where({\n status: 'open',\n })\n .limit(1)\n .select();\n\n if (!task) {\n return undefined;\n }\n\n const spec = this.parseSpec(task);\n\n const updateCount = await tx<RawDbTaskRow>('tasks')\n .where({ id: task.id, status: 'open' })\n .update({\n status: 'processing',\n last_heartbeat_at: this.db.fn.now(),\n // remove the secrets for non-recoverable tasks when moving to processing state.\n secrets: this.isRecoverableTask(spec) ? task.secrets : null,\n });\n\n if (updateCount < 1) {\n return undefined;\n }\n\n const ret: SerializedTask = {\n id: task.id,\n spec,\n status: 'processing',\n lastHeartbeatAt: task.last_heartbeat_at,\n createdAt: task.created_at,\n createdBy: task.created_by ?? undefined,\n state: this.getState(task),\n };\n\n this.events?.publish({\n topic: 'scaffolder.task',\n eventPayload: ret,\n });\n\n const secrets = this.parseTaskSecrets(task);\n return { ...ret, secrets };\n });\n }\n\n async heartbeatTask(taskId: string): Promise<void> {\n const updateCount = await this.db<RawDbTaskRow>('tasks')\n .where({ id: taskId, status: 'processing' })\n .update({\n last_heartbeat_at: this.db.fn.now(),\n });\n if (updateCount === 0) {\n throw new ConflictError(`No running task with taskId ${taskId} found`);\n }\n }\n\n async listStaleTasks(options: { timeoutS: number }): Promise<{\n tasks: { taskId: string; recovery?: TaskRecovery }[];\n }> {\n const { timeoutS } = options;\n const heartbeatInterval = intervalFromNowTill(timeoutS, this.db);\n const rawRows = await this.db<RawDbTaskRow>('tasks')\n .where('status', 'processing')\n .andWhere('last_heartbeat_at', '<=', heartbeatInterval);\n const tasks = rawRows.map(row => ({\n recovery: (JSON.parse(row.spec) as TaskSpec).EXPERIMENTAL_recovery,\n taskId: row.id,\n }));\n return { tasks };\n }\n\n async completeTask(options: {\n taskId: string;\n status: TaskStatus;\n eventBody: JsonObject;\n }): Promise<void> {\n const { taskId, status, eventBody } = options;\n\n let oldStatus: TaskStatus;\n if (['failed', 'completed', 'cancelled'].includes(status)) {\n oldStatus = 'processing';\n } else {\n throw new Error(\n `Invalid status update of run '${taskId}' to status '${status}'`,\n );\n }\n\n await this.db.transaction(async tx => {\n const [task] = await tx<RawDbTaskRow>('tasks')\n .where({\n id: taskId,\n })\n .limit(1)\n .select();\n\n const updateTask = async (criteria: {\n id: string;\n status?: TaskStatus;\n }) => {\n const updateCount = await tx<RawDbTaskRow>('tasks')\n .where(criteria)\n .update({\n status,\n secrets: null,\n });\n\n if (updateCount !== 1) {\n throw new ConflictError(\n `Failed to update status to '${status}' for taskId ${taskId}`,\n );\n }\n\n this.events?.publish({\n topic: 'scaffolder.task',\n eventPayload: {\n id: taskId,\n status: status,\n lastHeartbeatAt: task.last_heartbeat_at,\n createdAt: task.created_at,\n createdBy: task.created_by,\n state: this.getState(task),\n },\n });\n\n await tx<RawDbTaskEventRow>('task_events')\n .insert({\n task_id: taskId,\n event_type: 'completion',\n body: JSON.stringify(eventBody),\n })\n .returning('id');\n };\n\n if (status === 'cancelled') {\n await updateTask({\n id: taskId,\n });\n return;\n }\n\n if (task.status === 'cancelled') {\n return;\n }\n\n if (!task) {\n throw new Error(`No task with taskId ${taskId} found`);\n }\n if (task.status !== oldStatus) {\n throw new ConflictError(\n `Refusing to update status of run '${taskId}' to status '${status}' ` +\n `as it is currently '${task.status}', expected '${oldStatus}'`,\n );\n }\n\n await updateTask({\n id: taskId,\n status: oldStatus,\n });\n });\n }\n\n async emitLogEvent(\n options: TaskStoreEmitOptions<{ message: string } & JsonObject>,\n ): Promise<void> {\n const { taskId, body } = options;\n const serializedBody = JSON.stringify(body);\n await this.db<RawDbTaskEventRow>('task_events')\n .insert({\n task_id: taskId,\n event_type: 'log',\n body: serializedBody,\n })\n .returning('id');\n }\n\n async getTaskState({ taskId }: { taskId: string }): Promise<\n | {\n state: JsonObject;\n }\n | undefined\n > {\n const [result] = await this.db<RawDbTaskRow>('tasks')\n .where({ id: taskId })\n .select('state');\n return result.state ? JSON.parse(result.state) : undefined;\n }\n\n async saveTaskState(options: {\n taskId: string;\n state?: JsonObject;\n }): Promise<void> {\n if (options.state) {\n const serializedState = JSON.stringify({ state: options.state });\n await this.db<RawDbTaskRow>('tasks')\n .where({ id: options.taskId })\n .update({\n state: serializedState,\n });\n }\n }\n\n async listEvents(\n options: TaskStoreListEventsOptions,\n ): Promise<{ events: SerializedTaskEvent[] }> {\n const { isTaskRecoverable, taskId, after } = options;\n const rawEvents = await this.db<RawDbTaskEventRow>('task_events')\n .where({\n task_id: taskId,\n })\n .andWhere(builder => {\n if (typeof after === 'number') {\n builder.where('id', '>', after).orWhere('event_type', 'completion');\n }\n })\n .orderBy('id')\n .select();\n\n const events = rawEvents.map(event => {\n try {\n const body = JSON.parse(event.body) as SerializedTaskEvent['body'];\n return {\n id: Number(event.id),\n isTaskRecoverable,\n taskId,\n body,\n type: event.event_type,\n createdAt: parseSqlDateToIsoString(event.created_at),\n };\n } catch (error) {\n throw new Error(\n `Failed to parse event body from event taskId=${taskId} id=${event.id}, ${error}`,\n );\n }\n });\n\n return trimEventsTillLastRecovery(events);\n }\n\n async shutdownTask(options: TaskStoreShutDownTaskOptions): Promise<void> {\n const { taskId } = options;\n const message = `This task was marked as stale as it exceeded its timeout`;\n\n const statusStepEvents = (await this.listEvents({ taskId })).events.filter(\n ({ body }) => body?.stepId,\n );\n\n const completedSteps = statusStepEvents\n .filter(\n ({ body: { status } }) => status === 'failed' || status === 'completed',\n )\n .map(step => step.body.stepId);\n\n const hungProcessingSteps = statusStepEvents\n .filter(({ body: { status } }) => status === 'processing')\n .map(event => event.body.stepId)\n .filter(step => !completedSteps.includes(step));\n\n for (const step of hungProcessingSteps) {\n await this.emitLogEvent({\n taskId,\n body: {\n message,\n stepId: step,\n status: 'failed',\n },\n });\n }\n\n await this.completeTask({\n taskId,\n status: 'failed',\n eventBody: {\n message,\n },\n });\n }\n\n async rehydrateWorkspace(options: {\n taskId: string;\n targetPath: string;\n }): Promise<void> {\n const [result] = await this.db<RawDbTaskRow>('tasks')\n .where({ id: options.taskId })\n .select('workspace');\n\n await restoreWorkspace({\n path: options.targetPath,\n buffer: result.workspace,\n });\n }\n\n async cleanWorkspace({ taskId }: { taskId: string }): Promise<void> {\n await this.db('tasks').where({ id: taskId }).update({\n workspace: null,\n });\n }\n\n async serializeWorkspace(options: {\n path: string;\n taskId: string;\n }): Promise<void> {\n if (options.path) {\n const workspace = (await serializeWorkspace(options)).contents;\n await this.db<RawDbTaskRow>('tasks')\n .where({ id: options.taskId })\n .update({\n workspace,\n });\n }\n }\n\n async cancelTask(\n options: TaskStoreEmitOptions<{ message: string } & JsonObject>,\n ): Promise<void> {\n const { taskId, body } = options;\n const serializedBody = JSON.stringify(body);\n const [ret] = await this.db<RawDbTaskEventRow>('task_events')\n .insert({\n task_id: taskId,\n event_type: 'cancelled',\n body: serializedBody,\n })\n .returning('id');\n\n this.events?.publish({\n topic: 'scaffolder.task',\n eventPayload: {\n id: ret.id,\n taskId,\n status: 'cancelled',\n body,\n },\n });\n }\n\n async retryTask(options: {\n secrets?: TaskSecrets;\n taskId: string;\n }): Promise<void> {\n const { secrets, taskId } = options;\n\n await this.db.transaction(async tx => {\n const updateCount = await tx<RawDbTaskRow>('tasks')\n .where('id', taskId)\n .whereIn('status', ['cancelled', 'completed', 'failed', 'skipped'])\n .update({\n ...(secrets && { secrets: JSON.stringify(secrets) }),\n status: 'open',\n last_heartbeat_at: this.db.fn.now(),\n });\n\n if (Number(updateCount) !== 1) {\n throw new ConflictError(`Task with taskId ${taskId} cannot be retried`);\n }\n\n const [task] = await tx<RawDbTaskRow>('tasks')\n .where('id', taskId)\n .select('id', 'spec');\n const taskSpec = JSON.parse(task.spec) as TaskSpec;\n\n /**\n * Once task is picked up, all event types are replayed.\n * We have to remove cancelled or completion event_type as these are as actions for frontend to perform.\n * In contrary, we send 'recovered' event_type to reset the state on the frontend side.\n *\n */\n await tx<RawDbTaskEventRow>('task_events')\n .where('task_id', task.id)\n .andWhere(q => q.whereIn('event_type', ['cancelled', 'completion']))\n .del();\n\n await tx<RawDbTaskEventRow>('task_events').insert({\n task_id: task.id,\n event_type: 'recovered',\n body: JSON.stringify({\n recoverStrategy:\n taskSpec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? 'none',\n }),\n });\n });\n }\n\n async recoverTasks(\n options: TaskStoreRecoverTaskOptions,\n ): Promise<{ ids: string[] }> {\n const taskIdsToRecover: string[] = [];\n const timeoutS = Duration.fromObject(options.timeout).as('seconds');\n\n await this.db.transaction(async tx => {\n const heartbeatInterval = intervalFromNowTill(timeoutS, this.db);\n\n const result = await tx<RawDbTaskRow>('tasks')\n .where('status', 'processing')\n .andWhere('last_heartbeat_at', '<=', heartbeatInterval)\n .update(\n {\n status: 'open',\n last_heartbeat_at: this.db.fn.now(),\n },\n ['id', 'spec'],\n );\n\n taskIdsToRecover.push(...result.map(i => i.id));\n\n for (const { id, spec } of result) {\n const taskSpec = JSON.parse(spec as string) as TaskSpec;\n const event = {\n recoverStrategy:\n taskSpec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? 'none',\n };\n const [ret] = await tx<RawDbTaskEventRow>('task_events')\n .insert({\n task_id: id,\n event_type: 'recovered',\n body: JSON.stringify(event),\n })\n .returning('id');\n\n this.events?.publish({\n topic: 'scaffolder.task',\n eventPayload: {\n id: ret.id,\n taskId: id,\n status: 'recovered',\n body: event,\n },\n });\n }\n });\n\n return { ids: taskIdsToRecover };\n }\n}\n"],"names":["resolvePackagePath","DateTime","isNotCriteria","compact","isOrCriteria","isAndCriteria","flattenParams","NotFoundError","uuid","ConflictError","intervalFromNowTill","trimEventsTillLastRecovery","restoreWorkspace","serializeWorkspace","Duration"],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ 'use strict';
2
+
3
+ class DatabaseWorkspaceProvider {
4
+ storage;
5
+ static create(storage) {
6
+ return new DatabaseWorkspaceProvider(storage);
7
+ }
8
+ constructor(storage) {
9
+ this.storage = storage;
10
+ }
11
+ async serializeWorkspace(options) {
12
+ await this.storage.serializeWorkspace?.(options);
13
+ }
14
+ async rehydrateWorkspace(options) {
15
+ return this.storage.rehydrateWorkspace?.(options);
16
+ }
17
+ async cleanWorkspace(options) {
18
+ return this.storage.cleanWorkspace?.(options);
19
+ }
20
+ }
21
+
22
+ exports.DatabaseWorkspaceProvider = DatabaseWorkspaceProvider;
23
+ //# sourceMappingURL=DatabaseWorkspaceProvider.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DatabaseWorkspaceProvider.cjs.js","sources":["../../../src/scaffolder/tasks/DatabaseWorkspaceProvider.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 { TaskStore } from './types';\n\nimport { WorkspaceProvider } from '@backstage/plugin-scaffolder-node/alpha';\n\nexport class DatabaseWorkspaceProvider implements WorkspaceProvider {\n private readonly storage: TaskStore;\n\n static create(storage: TaskStore) {\n return new DatabaseWorkspaceProvider(storage);\n }\n\n private constructor(storage: TaskStore) {\n this.storage = storage;\n }\n\n public async serializeWorkspace(options: {\n path: string;\n taskId: string;\n }): Promise<void> {\n await this.storage.serializeWorkspace?.(options);\n }\n\n public async rehydrateWorkspace(options: {\n taskId: string;\n targetPath: string;\n }): Promise<void> {\n return this.storage.rehydrateWorkspace?.(options);\n }\n\n public async cleanWorkspace(options: { taskId: string }): Promise<void> {\n return this.storage.cleanWorkspace?.(options);\n }\n}\n"],"names":[],"mappings":";;AAoBO,MAAM,yBAAA,CAAuD;AAAA,EACjD,OAAA;AAAA,EAEjB,OAAO,OAAO,OAAA,EAAoB;AAChC,IAAA,OAAO,IAAI,0BAA0B,OAAO,CAAA;AAAA,EAC9C;AAAA,EAEQ,YAAY,OAAA,EAAoB;AACtC,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AAAA,EAEA,MAAa,mBAAmB,OAAA,EAGd;AAChB,IAAA,MAAM,IAAA,CAAK,OAAA,CAAQ,kBAAA,GAAqB,OAAO,CAAA;AAAA,EACjD;AAAA,EAEA,MAAa,mBAAmB,OAAA,EAGd;AAChB,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,kBAAA,GAAqB,OAAO,CAAA;AAAA,EAClD;AAAA,EAEA,MAAa,eAAe,OAAA,EAA4C;AACtE,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,cAAA,GAAiB,OAAO,CAAA;AAAA,EAC9C;AACF;;;;"}