@backstage/plugin-scaffolder-backend 2.0.1-next.1 → 2.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,69 @@
1
1
  # @backstage/plugin-scaffolder-backend
2
2
 
3
+ ## 2.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c1ce316: BREAKING `/alpha`: Converted `scaffolder.task.read` and `scaffolder.task.cancel` into Resource Permissions.
8
+
9
+ BREAKING `/alpha`: Added a new scaffolder rule `isTaskOwner` for `scaffolder.task.read` and `scaffolder.task.cancel` to allow for conditional permission policies such as restricting access to tasks and task events based on task creators.
10
+
11
+ BREAKING `/alpha`: Retrying a task now requires both `scaffolder.task.read` and `scaffolder.task.create` permissions, replacing the previous requirement of `scaffolder.task.read` and `scaffolder.task.cancel`.
12
+
13
+ ### Patch Changes
14
+
15
+ - 424610a: Scaffolder audit Log now includes taskId and createdBy
16
+ - dbde180: An internal refactor which adds additional types to experimental checkpoints
17
+ - fc70b43: Replaced deprecated uses of `@backstage/backend-common` with the equivalents in `@backstage/backend-defaults` and `@backstage/backend-plugin-api`.
18
+ - Updated dependencies
19
+ - @backstage/config@1.3.3
20
+ - @backstage/plugin-permission-common@0.9.1
21
+ - @backstage/plugin-permission-node@0.10.2
22
+ - @backstage/catalog-model@1.7.5
23
+ - @backstage/backend-defaults@0.11.1
24
+ - @backstage/plugin-scaffolder-node@0.10.0
25
+ - @backstage/integration@1.17.1
26
+ - @backstage/plugin-scaffolder-backend-module-github@0.8.1
27
+ - @backstage/plugin-scaffolder-common@1.6.0
28
+ - @backstage/backend-plugin-api@1.4.1
29
+ - @backstage/plugin-auth-node@0.6.5
30
+ - @backstage/plugin-bitbucket-cloud-common@0.3.1
31
+ - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.10
32
+ - @backstage/plugin-catalog-node@1.17.2
33
+ - @backstage/plugin-events-node@0.4.13
34
+ - @backstage/plugin-scaffolder-backend-module-azure@0.2.11
35
+ - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.12
36
+ - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.11
37
+ - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.11
38
+ - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.11
39
+ - @backstage/plugin-scaffolder-backend-module-gitea@0.2.11
40
+ - @backstage/plugin-scaffolder-backend-module-gitlab@0.9.3
41
+
42
+ ## 2.1.0-next.2
43
+
44
+ ### Minor Changes
45
+
46
+ - c1ce316: BREAKING `/alpha`: Converted `scaffolder.task.read` and `scaffolder.task.cancel` into Resource Permissions.
47
+
48
+ BREAKING `/alpha`: Added a new scaffolder rule `isTaskOwner` for `scaffolder.task.read` and `scaffolder.task.cancel` to allow for conditional permission policies such as restricting access to tasks and task events based on task creators.
49
+
50
+ BREAKING `/alpha`: Retrying a task now requires both `scaffolder.task.read` and `scaffolder.task.create` permissions, replacing the previous requirement of `scaffolder.task.read` and `scaffolder.task.cancel`.
51
+
52
+ ### Patch Changes
53
+
54
+ - Updated dependencies
55
+ - @backstage/plugin-scaffolder-common@1.6.0-next.1
56
+ - @backstage/plugin-scaffolder-node@0.10.0-next.2
57
+ - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.10-next.1
58
+ - @backstage/plugin-scaffolder-backend-module-azure@0.2.11-next.2
59
+ - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.12-next.2
60
+ - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.11-next.2
61
+ - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.11-next.2
62
+ - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.11-next.2
63
+ - @backstage/plugin-scaffolder-backend-module-gitea@0.2.11-next.2
64
+ - @backstage/plugin-scaffolder-backend-module-github@0.8.1-next.2
65
+ - @backstage/plugin-scaffolder-backend-module-gitlab@0.9.3-next.2
66
+
3
67
  ## 2.0.1-next.1
4
68
 
5
69
  ### Patch Changes
package/dist/alpha.cjs.js CHANGED
@@ -5,7 +5,9 @@ var alpha = require('./service/alpha.cjs.js');
5
5
 
6
6
 
7
7
  exports.createScaffolderActionConditionalDecision = alpha.createScaffolderActionConditionalDecision;
8
+ exports.createScaffolderTaskConditionalDecision = alpha.createScaffolderTaskConditionalDecision;
8
9
  exports.createScaffolderTemplateConditionalDecision = alpha.createScaffolderTemplateConditionalDecision;
9
10
  exports.scaffolderActionConditions = alpha.scaffolderActionConditions;
11
+ exports.scaffolderTaskConditions = alpha.scaffolderTaskConditions;
10
12
  exports.scaffolderTemplateConditions = alpha.scaffolderTemplateConditions;
11
13
  //# sourceMappingURL=alpha.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"alpha.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
1
+ {"version":3,"file":"alpha.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;"}
package/dist/alpha.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as _backstage_plugin_scaffolder_node from '@backstage/plugin-scaffolder-node';
1
2
  import * as _backstage_types from '@backstage/types';
2
3
  import * as _backstage_plugin_permission_node from '@backstage/plugin-permission-node';
3
4
  import * as _backstage_plugin_scaffolder_common from '@backstage/plugin-scaffolder-common';
@@ -87,5 +88,20 @@ declare const scaffolderActionConditions: _backstage_plugin_permission_node.Cond
87
88
  value?: string | undefined;
88
89
  }>;
89
90
  }>;
91
+ /**
92
+ * @alpha
93
+ */
94
+ declare const createScaffolderTaskConditionalDecision: (permission: _backstage_plugin_permission_common.ResourcePermission<"scaffolder-task">, conditions: _backstage_plugin_permission_common.PermissionCriteria<_backstage_plugin_permission_common.PermissionCondition<"scaffolder-task">>) => _backstage_plugin_permission_common.ConditionalPolicyDecision;
95
+ /**
96
+ * These conditions are used when creating conditional decisions for scaffolder
97
+ * tasks that are returned by authorization policies.
98
+ *
99
+ * @alpha
100
+ */
101
+ declare const scaffolderTaskConditions: _backstage_plugin_permission_node.Conditions<{
102
+ isTaskOwner: _backstage_plugin_permission_node.PermissionRule<_backstage_plugin_scaffolder_node.SerializedTask, _backstage_plugin_scaffolder_node.TaskFilter, "scaffolder-task", {
103
+ createdBy: string[];
104
+ }>;
105
+ }>;
90
106
 
91
- export { createScaffolderActionConditionalDecision, createScaffolderTemplateConditionalDecision, scaffolderActionConditions, scaffolderTemplateConditions };
107
+ export { createScaffolderActionConditionalDecision, createScaffolderTaskConditionalDecision, createScaffolderTemplateConditionalDecision, scaffolderActionConditions, scaffolderTaskConditions, scaffolderTemplateConditions };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
2
  import { UrlReaderService, DatabaseService, LoggerService, AuthService, BackstageCredentials, AuditorService } from '@backstage/backend-plugin-api';
3
3
  import * as _backstage_plugin_scaffolder_node from '@backstage/plugin-scaffolder-node';
4
- import { TemplateFilter, TemplateGlobal, TemplateAction, TaskSecrets, SerializedTask, TaskStatus, SerializedTaskEvent, TaskContext, TaskCompletionState, TaskBroker } from '@backstage/plugin-scaffolder-node';
4
+ import { TemplateFilter, TemplateGlobal, TemplateAction, TaskSecrets, SerializedTask, TaskStatus, TaskFilters, SerializedTaskEvent, TaskContext, TaskCompletionState, TaskBroker } from '@backstage/plugin-scaffolder-node';
5
5
  import { ScmIntegrations } from '@backstage/integration';
6
6
  import { CatalogService } from '@backstage/plugin-catalog-node';
7
7
  import { HumanDuration, JsonObject } from '@backstage/types';
@@ -9,10 +9,10 @@ import { Duration } from 'luxon';
9
9
  import { Knex } from 'knex';
10
10
  import * as _backstage_plugin_scaffolder_common from '@backstage/plugin-scaffolder-common';
11
11
  import { TaskSpec, TaskRecovery, TemplateEntityStepV1beta3, TemplateParametersV1beta3 } from '@backstage/plugin-scaffolder-common';
12
+ import { PermissionCriteria, PermissionEvaluator, PermissionRuleParams } from '@backstage/plugin-permission-common';
12
13
  import { EventsService } from '@backstage/plugin-events-node';
13
14
  import { Config } from '@backstage/config';
14
15
  import { WorkspaceProvider, UpdateTaskCheckpointOptions } from '@backstage/plugin-scaffolder-node/alpha';
15
- import { PermissionEvaluator, PermissionRuleParams } from '@backstage/plugin-permission-common';
16
16
  import { PermissionRule } from '@backstage/plugin-permission-node';
17
17
  import { RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, RESOURCE_TYPE_SCAFFOLDER_ACTION } from '@backstage/plugin-scaffolder-common/alpha';
18
18
 
@@ -349,6 +349,7 @@ interface TaskStore {
349
349
  limit?: number;
350
350
  offset?: number;
351
351
  };
352
+ permissionFilters?: PermissionCriteria<TaskFilters>;
352
353
  order?: {
353
354
  order: 'asc' | 'desc';
354
355
  field: string;
@@ -431,6 +432,8 @@ declare class DatabaseTaskStore implements TaskStore {
431
432
  private static runMigrations;
432
433
  private constructor();
433
434
  private getState;
435
+ private isTaskFilter;
436
+ private parseFilter;
434
437
  list(options: {
435
438
  createdBy?: string;
436
439
  status?: TaskStatus;
@@ -446,11 +449,13 @@ declare class DatabaseTaskStore implements TaskStore {
446
449
  order: 'asc' | 'desc';
447
450
  field: string;
448
451
  }[];
452
+ permissionFilters?: PermissionCriteria<TaskFilters>;
449
453
  }): Promise<{
450
454
  tasks: SerializedTask[];
451
455
  totalTasks?: number;
452
456
  }>;
453
457
  getTask(taskId: string): Promise<SerializedTask>;
458
+ private parseTaskRow;
454
459
  createTask(options: TaskStoreCreateTaskOptions): Promise<TaskStoreCreateTaskResult>;
455
460
  claimTask(): Promise<SerializedTask | undefined>;
456
461
  heartbeatTask(taskId: string): Promise<void>;
@@ -522,6 +527,7 @@ declare class TaskManager implements TaskContext {
522
527
  private heartbeatTimeoutId?;
523
528
  static create(task: CurrentClaimedTask, storage: TaskStore, abortSignal: AbortSignal, logger: LoggerService, auth?: AuthService, config?: Config, additionalWorkspaceProviders?: Record<string, WorkspaceProvider>): TaskManager;
524
529
  private constructor();
530
+ get taskId(): string;
525
531
  get spec(): _backstage_plugin_scaffolder_common.TaskSpecV1beta3;
526
532
  get cancelSignal(): AbortSignal;
527
533
  get secrets(): TaskSecrets | undefined;
@@ -8,6 +8,8 @@ var taskRecoveryHelper = require('./taskRecoveryHelper.cjs.js');
8
8
  var dbUtil = require('./dbUtil.cjs.js');
9
9
  var alpha = require('@backstage/plugin-scaffolder-node/alpha');
10
10
  var helpers = require('../../service/helpers.cjs.js');
11
+ var pluginPermissionNode = require('@backstage/plugin-permission-node');
12
+ var lodash = require('lodash');
11
13
 
12
14
  const migrationsDir = backendPluginApi.resolvePackagePath(
13
15
  "@backstage/plugin-scaffolder-backend",
@@ -90,15 +92,53 @@ class DatabaseTaskStore {
90
92
  );
91
93
  }
92
94
  }
95
+ isTaskFilter(filter) {
96
+ return filter.hasOwnProperty("key");
97
+ }
98
+ parseFilter(filter, query, db, negate = false) {
99
+ if (pluginPermissionNode.isNotCriteria(filter)) {
100
+ return this.parseFilter(filter.not, query, db, !negate);
101
+ }
102
+ if (this.isTaskFilter(filter)) {
103
+ const values = lodash.compact(filter.values) ?? [];
104
+ if (negate) {
105
+ query.whereNotIn(filter.key, values);
106
+ } else {
107
+ query.whereIn(filter.key, values);
108
+ }
109
+ return query;
110
+ }
111
+ return query[negate ? "andWhereNot" : "andWhere"]((subQuery) => {
112
+ if (pluginPermissionNode.isOrCriteria(filter)) {
113
+ for (const subFilter of filter.anyOf ?? []) {
114
+ subQuery.orWhere(
115
+ (subQueryInner) => this.parseFilter(subFilter, subQueryInner, db, false)
116
+ );
117
+ }
118
+ } else if (pluginPermissionNode.isAndCriteria(filter)) {
119
+ for (const subFilter of filter.allOf ?? []) {
120
+ subQuery.andWhere(
121
+ (subQueryInner) => this.parseFilter(subFilter, subQueryInner, db, false)
122
+ );
123
+ }
124
+ }
125
+ });
126
+ }
93
127
  async list(options) {
94
- const { createdBy, status, pagination, order, filters } = options ?? {};
128
+ const { createdBy, status, pagination, order, filters, permissionFilters } = options ?? {};
95
129
  const queryBuilder = this.db("tasks");
96
- if (createdBy || filters?.createdBy) {
97
- const arr = helpers.flattenParams(
98
- createdBy,
99
- filters?.createdBy
100
- );
101
- queryBuilder.whereIn("created_by", [...new Set(arr)]);
130
+ const createdByValues = helpers.flattenParams(
131
+ createdBy,
132
+ filters?.createdBy
133
+ );
134
+ const combinedPermissionFilters = createdByValues.length > 0 ? {
135
+ allOf: [
136
+ { key: "created_by", values: createdByValues },
137
+ ...permissionFilters ? [permissionFilters] : []
138
+ ]
139
+ } : permissionFilters;
140
+ if (combinedPermissionFilters) {
141
+ this.parseFilter(combinedPermissionFilters, queryBuilder, this.db);
102
142
  }
103
143
  if (status || filters?.status) {
104
144
  const arr = helpers.flattenParams(
@@ -142,23 +182,26 @@ class DatabaseTaskStore {
142
182
  throw new errors.NotFoundError(`No task with id '${taskId}' found`);
143
183
  }
144
184
  try {
145
- const spec = JSON.parse(result.spec);
146
- const secrets = result.secrets ? JSON.parse(result.secrets) : void 0;
147
- const state = this.getState(result);
148
- return {
149
- id: result.id,
150
- spec,
151
- status: result.status,
152
- lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at),
153
- createdAt: parseSqlDateToIsoString(result.created_at),
154
- createdBy: result.created_by ?? void 0,
155
- secrets,
156
- state
157
- };
185
+ return this.parseTaskRow(result);
158
186
  } catch (error) {
159
187
  throw new Error(`Failed to parse spec of task '${taskId}', ${error}`);
160
188
  }
161
189
  }
190
+ parseTaskRow(result) {
191
+ const spec = JSON.parse(result.spec);
192
+ const secrets = result.secrets ? JSON.parse(result.secrets) : void 0;
193
+ const state = this.getState(result);
194
+ return {
195
+ id: result.id,
196
+ spec,
197
+ status: result.status,
198
+ lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at),
199
+ createdAt: parseSqlDateToIsoString(result.created_at),
200
+ createdBy: result.created_by ?? void 0,
201
+ secrets,
202
+ state
203
+ };
204
+ }
162
205
  async createTask(options) {
163
206
  const taskId = uuid.v4();
164
207
  await this.db("tasks").insert({
@@ -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 { v4 as uuid } from 'uuid';\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 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';\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 * @deprecated this type is deprecated, and there will be a new way to create Workers in the next major version.\n * @public\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 * @deprecated this type is deprecated, and there will be a new way to create Workers in the next major version.\n * @public\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 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 }): Promise<{ tasks: SerializedTask[]; totalTasks?: number }> {\n const { createdBy, status, pagination, order, filters } = options ?? {};\n const queryBuilder = this.db<RawDbTaskRow & { count: number }>('tasks');\n\n if (createdBy || filters?.createdBy) {\n const arr: string[] = flattenParams<string>(\n createdBy,\n filters?.createdBy,\n );\n queryBuilder.whereIn('created_by', [...new Set(arr)]);\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 return { tasks, totalTasks: count };\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 const spec = JSON.parse(result.spec);\n const secrets = result.secrets ? JSON.parse(result.secrets) : undefined;\n const state = this.getState(result);\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 } catch (error) {\n throw new Error(`Failed to parse spec of task '${taskId}', ${error}`);\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 JsonObject;\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 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","flattenParams","NotFoundError","uuid","ConflictError","intervalFromNowTill","trimEventsTillLastRecovery","restoreWorkspace","serializeWorkspace","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 { v4 as uuid } from 'uuid';\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 * @deprecated this type is deprecated, and there will be a new way to create Workers in the next major version.\n * @public\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 * @deprecated this type is deprecated, and there will be a new way to create Workers in the next major version.\n * @public\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 return { tasks, totalTasks: count };\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 JsonObject;\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 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","restoreWorkspace","serializeWorkspace","Duration"],"mappings":"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"}
@@ -39,6 +39,9 @@ class TaskManager {
39
39
  agent.startTimeout();
40
40
  return agent;
41
41
  }
42
+ get taskId() {
43
+ return this.task.taskId;
44
+ }
42
45
  get spec() {
43
46
  return this.task.spec;
44
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"StorageTaskBroker.cjs.js","sources":["../../../src/scaffolder/tasks/StorageTaskBroker.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 AuditorService,\n AuthService,\n BackstageCredentials,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport {\n SerializedTask,\n SerializedTaskEvent,\n TaskBroker,\n TaskBrokerDispatchOptions,\n TaskCompletionState,\n TaskContext,\n TaskSecrets,\n TaskStatus,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n CheckpointState,\n WorkspaceProvider,\n UpdateTaskCheckpointOptions,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport { JsonObject, Observable, createDeferred } from '@backstage/types';\nimport ObservableImpl from 'zen-observable';\nimport { DefaultWorkspaceService, WorkspaceService } from './WorkspaceService';\nimport { readDuration } from './helper';\nimport { InternalTaskSecrets, TaskStore } from './types';\n\ntype TaskState = {\n checkpoints: CheckpointState;\n};\n/**\n * TaskManager\n * @deprecated this type is deprecated, and there will be a new way to create Workers in the next major version.\n * @public\n */\nexport class TaskManager implements TaskContext {\n private isDone = false;\n\n private heartbeatTimeoutId?: ReturnType<typeof setInterval>;\n\n static create(\n task: CurrentClaimedTask,\n storage: TaskStore,\n abortSignal: AbortSignal,\n logger: LoggerService,\n auth?: AuthService,\n config?: Config,\n additionalWorkspaceProviders?: Record<string, WorkspaceProvider>,\n ) {\n const workspaceService = DefaultWorkspaceService.create(\n task,\n storage,\n additionalWorkspaceProviders,\n config,\n );\n\n const agent = new TaskManager(\n task,\n storage,\n abortSignal,\n logger,\n workspaceService,\n auth,\n );\n agent.startTimeout();\n return agent;\n }\n\n // Runs heartbeat internally\n private constructor(\n private readonly task: CurrentClaimedTask,\n private readonly storage: TaskStore,\n private readonly signal: AbortSignal,\n private readonly logger: LoggerService,\n private readonly workspaceService: WorkspaceService,\n private readonly auth?: AuthService,\n ) {}\n\n get spec() {\n return this.task.spec;\n }\n\n get cancelSignal() {\n return this.signal;\n }\n\n get secrets() {\n return this.task.secrets;\n }\n\n get createdBy() {\n return this.task.createdBy;\n }\n\n async getWorkspaceName() {\n return this.task.taskId;\n }\n\n async rehydrateWorkspace?(options: {\n taskId: string;\n targetPath: string;\n }): Promise<void> {\n await this.workspaceService.rehydrateWorkspace(options);\n }\n\n get done() {\n return this.isDone;\n }\n\n async emitLog(message: string, logMetadata?: JsonObject): Promise<void> {\n await this.storage.emitLogEvent({\n taskId: this.task.taskId,\n body: { message, ...logMetadata },\n });\n }\n\n async getTaskState?(): Promise<\n | {\n state?: JsonObject;\n }\n | undefined\n > {\n return this.storage.getTaskState?.({ taskId: this.task.taskId });\n }\n\n async updateCheckpoint?(options: UpdateTaskCheckpointOptions): Promise<void> {\n const { key, ...value } = options;\n\n if (this.task.state) {\n (this.task.state as TaskState).checkpoints[key] = value;\n } else {\n this.task.state = { checkpoints: { [key]: value } };\n }\n await this.storage.saveTaskState?.({\n taskId: this.task.taskId,\n state: this.task.state,\n });\n }\n\n async serializeWorkspace?(options: { path: string }): Promise<void> {\n await this.workspaceService.serializeWorkspace(options);\n }\n\n async cleanWorkspace?(): Promise<void> {\n await this.workspaceService.cleanWorkspace();\n }\n\n async complete(\n result: TaskCompletionState,\n metadata?: JsonObject,\n ): Promise<void> {\n await this.storage.completeTask({\n taskId: this.task.taskId,\n status: result === 'failed' ? 'failed' : 'completed',\n eventBody: {\n message: `Run completed with status: ${result}`,\n ...metadata,\n },\n });\n this.isDone = true;\n if (this.heartbeatTimeoutId) {\n clearTimeout(this.heartbeatTimeoutId);\n }\n }\n\n private startTimeout() {\n this.heartbeatTimeoutId = setTimeout(async () => {\n try {\n await this.storage.heartbeatTask(this.task.taskId);\n this.startTimeout();\n } catch (error) {\n this.isDone = true;\n\n this.logger.error(\n `Heartbeat for task ${this.task.taskId} failed`,\n error,\n );\n }\n }, 1000);\n }\n\n async getInitiatorCredentials(): Promise<BackstageCredentials> {\n const secrets = this.task.secrets as InternalTaskSecrets;\n\n if (secrets && secrets.__initiatorCredentials) {\n return JSON.parse(secrets.__initiatorCredentials);\n }\n if (!this.auth) {\n throw new Error(\n 'Failed to create none credentials in scaffolder task. The TaskManager has not been initialized with an auth service implementation',\n );\n }\n return this.auth.getNoneCredentials();\n }\n}\n\n/**\n * Stores the state of the current claimed task passed to the TaskContext\n *\n * @public\n */\nexport interface CurrentClaimedTask {\n /**\n * The TaskSpec of the current claimed task.\n */\n spec: TaskSpec;\n /**\n * The uuid of the current claimed task.\n */\n taskId: string;\n /**\n * The secrets that are stored with the task.\n */\n secrets?: TaskSecrets;\n /**\n * The state of checkpoints of the task.\n */\n state?: JsonObject;\n /**\n * The creator of the task.\n */\n createdBy?: string;\n /**\n * The workspace of the task.\n */\n workspace?: Promise<Buffer>;\n}\n\nexport class StorageTaskBroker implements TaskBroker {\n constructor(\n private readonly storage: TaskStore,\n private readonly logger: LoggerService,\n private readonly config?: Config,\n private readonly auth?: AuthService,\n private readonly additionalWorkspaceProviders?: Record<\n string,\n WorkspaceProvider\n >,\n private readonly auditor?: AuditorService,\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 }): Promise<{ tasks: SerializedTask[]; totalTasks?: number }> {\n if (!this.storage.list) {\n throw new Error(\n 'TaskStore does not implement the list method. Please implement the list method to be able to list tasks',\n );\n }\n return await this.storage.list(options ?? {});\n }\n\n private deferredDispatch = createDeferred();\n\n private async registerCancellable(\n taskId: string,\n abortController: AbortController,\n ) {\n let shouldUnsubscribe = false;\n const subscription = this.event$({ taskId, after: undefined }).subscribe({\n error: _ => {\n subscription.unsubscribe();\n },\n next: ({ events }) => {\n for (const event of events) {\n if (event.type === 'cancelled') {\n abortController.abort();\n shouldUnsubscribe = true;\n }\n\n if (event.type === 'completion' && !event.isTaskRecoverable) {\n shouldUnsubscribe = true;\n }\n }\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n }\n },\n });\n }\n\n public async recoverTasks(): Promise<void> {\n const enabled =\n this.config?.getOptionalBoolean('scaffolder.EXPERIMENTAL_recoverTasks') ??\n false;\n\n if (enabled) {\n const defaultTimeout = { seconds: 30 };\n const timeout = readDuration(\n this.config,\n 'scaffolder.EXPERIMENTAL_recoverTasksTimeout',\n defaultTimeout,\n );\n const { ids: recoveredTaskIds } = (await this.storage.recoverTasks?.({\n timeout,\n })) ?? { ids: [] };\n if (recoveredTaskIds.length > 0) {\n this.signalDispatch();\n }\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.claim}\n */\n async claim(): Promise<TaskContext> {\n for (;;) {\n const pendingTask = await this.storage.claimTask();\n if (pendingTask) {\n const abortController = new AbortController();\n await this.registerCancellable(pendingTask.id, abortController);\n return TaskManager.create(\n {\n taskId: pendingTask.id,\n spec: pendingTask.spec,\n secrets: pendingTask.secrets,\n createdBy: pendingTask.createdBy,\n state: pendingTask.state,\n },\n this.storage,\n abortController.signal,\n this.logger,\n this.auth,\n this.config,\n this.additionalWorkspaceProviders,\n );\n }\n\n await this.waitForDispatch();\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.dispatch}\n */\n async dispatch(\n options: TaskBrokerDispatchOptions,\n ): Promise<{ taskId: string }> {\n const taskRow = await this.storage.createTask(options);\n this.signalDispatch();\n return {\n taskId: taskRow.taskId,\n };\n }\n\n /**\n * {@inheritdoc TaskBroker.get}\n */\n async get(taskId: string): Promise<SerializedTask> {\n return this.storage.getTask(taskId);\n }\n\n /**\n * {@inheritdoc TaskBroker.event$}\n */\n event$(options: {\n taskId: string;\n after?: number;\n }): Observable<{ events: SerializedTaskEvent[] }> {\n return new ObservableImpl(observer => {\n const { taskId } = options;\n\n let after = options.after;\n let cancelled = false;\n\n (async () => {\n const task = await this.storage.getTask(taskId);\n const isTaskRecoverable =\n task.spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ===\n 'startOver';\n\n while (!cancelled) {\n const result = await this.storage.listEvents({\n isTaskRecoverable,\n taskId,\n after,\n });\n const { events } = result;\n if (events.length) {\n after = events[events.length - 1].id;\n observer.next(result);\n }\n\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n })();\n\n return () => {\n cancelled = true;\n };\n });\n }\n\n /**\n * {@inheritdoc TaskBroker.vacuumTasks}\n */\n async vacuumTasks(options: { timeoutS: number }): Promise<void> {\n const { tasks } = await this.storage.listStaleTasks(options);\n await Promise.all(\n tasks.map(async task => {\n const auditorEvent = await this.auditor?.createEvent({\n eventId: 'task',\n severityLevel: 'medium',\n meta: {\n actionType: 'stale-cancel',\n taskId: task.taskId,\n },\n });\n try {\n await this.storage.completeTask({\n taskId: task.taskId,\n status: 'failed',\n eventBody: {\n message:\n 'The task was cancelled because the task worker lost connection to the task broker',\n },\n });\n await auditorEvent?.success();\n } catch (error) {\n this.logger.warn(`Failed to cancel task '${task.taskId}', ${error}`);\n await auditorEvent?.fail({ error: error });\n }\n }),\n );\n }\n\n private waitForDispatch() {\n return this.deferredDispatch;\n }\n\n private signalDispatch() {\n this.deferredDispatch.resolve();\n this.deferredDispatch = createDeferred();\n }\n\n async cancel(taskId: string) {\n const { events } = await this.storage.listEvents({ taskId });\n const currentStepId =\n events.length > 0\n ? events\n .filter(({ body }) => body?.stepId)\n .reduce((prev, curr) => (prev.id > curr.id ? prev : curr)).body\n .stepId\n : 0;\n\n await this.storage.cancelTask?.({\n taskId,\n body: {\n message: `Step ${currentStepId} has been cancelled.`,\n stepId: currentStepId,\n status: 'cancelled',\n },\n });\n }\n\n async retry?(options: {\n secrets?: TaskSecrets;\n taskId: string;\n }): Promise<void> {\n await this.storage.retryTask?.(options);\n this.signalDispatch();\n }\n}\n"],"names":["DefaultWorkspaceService","createDeferred","readDuration","ObservableImpl"],"mappings":"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"}
1
+ {"version":3,"file":"StorageTaskBroker.cjs.js","sources":["../../../src/scaffolder/tasks/StorageTaskBroker.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 AuditorService,\n AuthService,\n BackstageCredentials,\n LoggerService,\n} from '@backstage/backend-plugin-api';\nimport { Config } from '@backstage/config';\nimport { TaskSpec } from '@backstage/plugin-scaffolder-common';\nimport {\n SerializedTask,\n SerializedTaskEvent,\n TaskBroker,\n TaskBrokerDispatchOptions,\n TaskCompletionState,\n TaskContext,\n TaskFilters,\n TaskSecrets,\n TaskStatus,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n CheckpointState,\n WorkspaceProvider,\n UpdateTaskCheckpointOptions,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport { JsonObject, Observable, createDeferred } from '@backstage/types';\nimport ObservableImpl from 'zen-observable';\nimport { DefaultWorkspaceService, WorkspaceService } from './WorkspaceService';\nimport { readDuration } from './helper';\nimport { InternalTaskSecrets, TaskStore } from './types';\nimport { PermissionCriteria } from '@backstage/plugin-permission-common';\n\ntype TaskState = {\n checkpoints: CheckpointState;\n};\n/**\n * TaskManager\n * @deprecated this type is deprecated, and there will be a new way to create Workers in the next major version.\n * @public\n */\nexport class TaskManager implements TaskContext {\n private isDone = false;\n\n private heartbeatTimeoutId?: ReturnType<typeof setInterval>;\n\n static create(\n task: CurrentClaimedTask,\n storage: TaskStore,\n abortSignal: AbortSignal,\n logger: LoggerService,\n auth?: AuthService,\n config?: Config,\n additionalWorkspaceProviders?: Record<string, WorkspaceProvider>,\n ) {\n const workspaceService = DefaultWorkspaceService.create(\n task,\n storage,\n additionalWorkspaceProviders,\n config,\n );\n\n const agent = new TaskManager(\n task,\n storage,\n abortSignal,\n logger,\n workspaceService,\n auth,\n );\n agent.startTimeout();\n return agent;\n }\n\n // Runs heartbeat internally\n private constructor(\n private readonly task: CurrentClaimedTask,\n private readonly storage: TaskStore,\n private readonly signal: AbortSignal,\n private readonly logger: LoggerService,\n private readonly workspaceService: WorkspaceService,\n private readonly auth?: AuthService,\n ) {}\n\n get taskId() {\n return this.task.taskId;\n }\n\n get spec() {\n return this.task.spec;\n }\n\n get cancelSignal() {\n return this.signal;\n }\n\n get secrets() {\n return this.task.secrets;\n }\n\n get createdBy() {\n return this.task.createdBy;\n }\n\n async getWorkspaceName() {\n return this.task.taskId;\n }\n\n async rehydrateWorkspace?(options: {\n taskId: string;\n targetPath: string;\n }): Promise<void> {\n await this.workspaceService.rehydrateWorkspace(options);\n }\n\n get done() {\n return this.isDone;\n }\n\n async emitLog(message: string, logMetadata?: JsonObject): Promise<void> {\n await this.storage.emitLogEvent({\n taskId: this.task.taskId,\n body: { message, ...logMetadata },\n });\n }\n\n async getTaskState?(): Promise<\n | {\n state?: JsonObject;\n }\n | undefined\n > {\n return this.storage.getTaskState?.({ taskId: this.task.taskId });\n }\n\n async updateCheckpoint?(options: UpdateTaskCheckpointOptions): Promise<void> {\n const { key, ...value } = options;\n\n if (this.task.state) {\n (this.task.state as TaskState).checkpoints[key] = value;\n } else {\n this.task.state = { checkpoints: { [key]: value } };\n }\n await this.storage.saveTaskState?.({\n taskId: this.task.taskId,\n state: this.task.state,\n });\n }\n\n async serializeWorkspace?(options: { path: string }): Promise<void> {\n await this.workspaceService.serializeWorkspace(options);\n }\n\n async cleanWorkspace?(): Promise<void> {\n await this.workspaceService.cleanWorkspace();\n }\n\n async complete(\n result: TaskCompletionState,\n metadata?: JsonObject,\n ): Promise<void> {\n await this.storage.completeTask({\n taskId: this.task.taskId,\n status: result === 'failed' ? 'failed' : 'completed',\n eventBody: {\n message: `Run completed with status: ${result}`,\n ...metadata,\n },\n });\n this.isDone = true;\n if (this.heartbeatTimeoutId) {\n clearTimeout(this.heartbeatTimeoutId);\n }\n }\n\n private startTimeout() {\n this.heartbeatTimeoutId = setTimeout(async () => {\n try {\n await this.storage.heartbeatTask(this.task.taskId);\n this.startTimeout();\n } catch (error) {\n this.isDone = true;\n\n this.logger.error(\n `Heartbeat for task ${this.task.taskId} failed`,\n error,\n );\n }\n }, 1000);\n }\n\n async getInitiatorCredentials(): Promise<BackstageCredentials> {\n const secrets = this.task.secrets as InternalTaskSecrets;\n\n if (secrets && secrets.__initiatorCredentials) {\n return JSON.parse(secrets.__initiatorCredentials);\n }\n if (!this.auth) {\n throw new Error(\n 'Failed to create none credentials in scaffolder task. The TaskManager has not been initialized with an auth service implementation',\n );\n }\n return this.auth.getNoneCredentials();\n }\n}\n\n/**\n * Stores the state of the current claimed task passed to the TaskContext\n *\n * @public\n */\nexport interface CurrentClaimedTask {\n /**\n * The TaskSpec of the current claimed task.\n */\n spec: TaskSpec;\n /**\n * The uuid of the current claimed task.\n */\n taskId: string;\n /**\n * The secrets that are stored with the task.\n */\n secrets?: TaskSecrets;\n /**\n * The state of checkpoints of the task.\n */\n state?: JsonObject;\n /**\n * The creator of the task.\n */\n createdBy?: string;\n /**\n * The workspace of the task.\n */\n workspace?: Promise<Buffer>;\n}\n\nexport class StorageTaskBroker implements TaskBroker {\n constructor(\n private readonly storage: TaskStore,\n private readonly logger: LoggerService,\n private readonly config?: Config,\n private readonly auth?: AuthService,\n private readonly additionalWorkspaceProviders?: Record<\n string,\n WorkspaceProvider\n >,\n private readonly auditor?: AuditorService,\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 if (!this.storage.list) {\n throw new Error(\n 'TaskStore does not implement the list method. Please implement the list method to be able to list tasks',\n );\n }\n return await this.storage.list(options ?? {});\n }\n\n private deferredDispatch = createDeferred();\n\n private async registerCancellable(\n taskId: string,\n abortController: AbortController,\n ) {\n let shouldUnsubscribe = false;\n const subscription = this.event$({ taskId, after: undefined }).subscribe({\n error: _ => {\n subscription.unsubscribe();\n },\n next: ({ events }) => {\n for (const event of events) {\n if (event.type === 'cancelled') {\n abortController.abort();\n shouldUnsubscribe = true;\n }\n\n if (event.type === 'completion' && !event.isTaskRecoverable) {\n shouldUnsubscribe = true;\n }\n }\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n }\n },\n });\n }\n\n public async recoverTasks(): Promise<void> {\n const enabled =\n this.config?.getOptionalBoolean('scaffolder.EXPERIMENTAL_recoverTasks') ??\n false;\n\n if (enabled) {\n const defaultTimeout = { seconds: 30 };\n const timeout = readDuration(\n this.config,\n 'scaffolder.EXPERIMENTAL_recoverTasksTimeout',\n defaultTimeout,\n );\n const { ids: recoveredTaskIds } = (await this.storage.recoverTasks?.({\n timeout,\n })) ?? { ids: [] };\n if (recoveredTaskIds.length > 0) {\n this.signalDispatch();\n }\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.claim}\n */\n async claim(): Promise<TaskContext> {\n for (;;) {\n const pendingTask = await this.storage.claimTask();\n if (pendingTask) {\n const abortController = new AbortController();\n await this.registerCancellable(pendingTask.id, abortController);\n return TaskManager.create(\n {\n taskId: pendingTask.id,\n spec: pendingTask.spec,\n secrets: pendingTask.secrets,\n createdBy: pendingTask.createdBy,\n state: pendingTask.state,\n },\n this.storage,\n abortController.signal,\n this.logger,\n this.auth,\n this.config,\n this.additionalWorkspaceProviders,\n );\n }\n\n await this.waitForDispatch();\n }\n }\n\n /**\n * {@inheritdoc TaskBroker.dispatch}\n */\n async dispatch(\n options: TaskBrokerDispatchOptions,\n ): Promise<{ taskId: string }> {\n const taskRow = await this.storage.createTask(options);\n this.signalDispatch();\n return {\n taskId: taskRow.taskId,\n };\n }\n\n /**\n * {@inheritdoc TaskBroker.get}\n */\n async get(taskId: string): Promise<SerializedTask> {\n return this.storage.getTask(taskId);\n }\n\n /**\n * {@inheritdoc TaskBroker.event$}\n */\n event$(options: {\n taskId: string;\n after?: number;\n }): Observable<{ events: SerializedTaskEvent[] }> {\n return new ObservableImpl(observer => {\n const { taskId } = options;\n\n let after = options.after;\n let cancelled = false;\n\n (async () => {\n const task = await this.storage.getTask(taskId);\n const isTaskRecoverable =\n task.spec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ===\n 'startOver';\n\n while (!cancelled) {\n const result = await this.storage.listEvents({\n isTaskRecoverable,\n taskId,\n after,\n });\n const { events } = result;\n if (events.length) {\n after = events[events.length - 1].id;\n observer.next(result);\n }\n\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n })();\n\n return () => {\n cancelled = true;\n };\n });\n }\n\n /**\n * {@inheritdoc TaskBroker.vacuumTasks}\n */\n async vacuumTasks(options: { timeoutS: number }): Promise<void> {\n const { tasks } = await this.storage.listStaleTasks(options);\n await Promise.all(\n tasks.map(async task => {\n const auditorEvent = await this.auditor?.createEvent({\n eventId: 'task',\n severityLevel: 'medium',\n meta: {\n actionType: 'stale-cancel',\n taskId: task.taskId,\n },\n });\n try {\n await this.storage.completeTask({\n taskId: task.taskId,\n status: 'failed',\n eventBody: {\n message:\n 'The task was cancelled because the task worker lost connection to the task broker',\n },\n });\n await auditorEvent?.success();\n } catch (error) {\n this.logger.warn(`Failed to cancel task '${task.taskId}', ${error}`);\n await auditorEvent?.fail({ error: error });\n }\n }),\n );\n }\n\n private waitForDispatch() {\n return this.deferredDispatch;\n }\n\n private signalDispatch() {\n this.deferredDispatch.resolve();\n this.deferredDispatch = createDeferred();\n }\n\n async cancel(taskId: string) {\n const { events } = await this.storage.listEvents({ taskId });\n const currentStepId =\n events.length > 0\n ? events\n .filter(({ body }) => body?.stepId)\n .reduce((prev, curr) => (prev.id > curr.id ? prev : curr)).body\n .stepId\n : 0;\n\n await this.storage.cancelTask?.({\n taskId,\n body: {\n message: `Step ${currentStepId} has been cancelled.`,\n stepId: currentStepId,\n status: 'cancelled',\n },\n });\n }\n\n async retry?(options: {\n secrets?: TaskSecrets;\n taskId: string;\n }): Promise<void> {\n await this.storage.retryTask?.(options);\n this.signalDispatch();\n }\n}\n"],"names":["DefaultWorkspaceService","createDeferred","readDuration","ObservableImpl"],"mappings":";;;;;;;;;;;AAuDO,MAAM,WAAmC,CAAA;AAAA;AAAA,EAkCtC,YACW,IACA,EAAA,OAAA,EACA,MACA,EAAA,MAAA,EACA,kBACA,IACjB,EAAA;AANiB,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,gBAAA,GAAA,gBAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAAA;AAChB,EAxCK,MAAS,GAAA,KAAA;AAAA,EAET,kBAAA;AAAA,EAER,OAAO,OACL,IACA,EAAA,OAAA,EACA,aACA,MACA,EAAA,IAAA,EACA,QACA,4BACA,EAAA;AACA,IAAA,MAAM,mBAAmBA,wCAAwB,CAAA,MAAA;AAAA,MAC/C,IAAA;AAAA,MACA,OAAA;AAAA,MACA,4BAAA;AAAA,MACA;AAAA,KACF;AAEA,IAAA,MAAM,QAAQ,IAAI,WAAA;AAAA,MAChB,IAAA;AAAA,MACA,OAAA;AAAA,MACA,WAAA;AAAA,MACA,MAAA;AAAA,MACA,gBAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,KAAA,CAAM,YAAa,EAAA;AACnB,IAAO,OAAA,KAAA;AAAA;AACT,EAYA,IAAI,MAAS,GAAA;AACX,IAAA,OAAO,KAAK,IAAK,CAAA,MAAA;AAAA;AACnB,EAEA,IAAI,IAAO,GAAA;AACT,IAAA,OAAO,KAAK,IAAK,CAAA,IAAA;AAAA;AACnB,EAEA,IAAI,YAAe,GAAA;AACjB,IAAA,OAAO,IAAK,CAAA,MAAA;AAAA;AACd,EAEA,IAAI,OAAU,GAAA;AACZ,IAAA,OAAO,KAAK,IAAK,CAAA,OAAA;AAAA;AACnB,EAEA,IAAI,SAAY,GAAA;AACd,IAAA,OAAO,KAAK,IAAK,CAAA,SAAA;AAAA;AACnB,EAEA,MAAM,gBAAmB,GAAA;AACvB,IAAA,OAAO,KAAK,IAAK,CAAA,MAAA;AAAA;AACnB,EAEA,MAAM,mBAAoB,OAGR,EAAA;AAChB,IAAM,MAAA,IAAA,CAAK,gBAAiB,CAAA,kBAAA,CAAmB,OAAO,CAAA;AAAA;AACxD,EAEA,IAAI,IAAO,GAAA;AACT,IAAA,OAAO,IAAK,CAAA,MAAA;AAAA;AACd,EAEA,MAAM,OAAQ,CAAA,OAAA,EAAiB,WAAyC,EAAA;AACtE,IAAM,MAAA,IAAA,CAAK,QAAQ,YAAa,CAAA;AAAA,MAC9B,MAAA,EAAQ,KAAK,IAAK,CAAA,MAAA;AAAA,MAClB,IAAM,EAAA,EAAE,OAAS,EAAA,GAAG,WAAY;AAAA,KACjC,CAAA;AAAA;AACH,EAEA,MAAM,YAKJ,GAAA;AACA,IAAO,OAAA,IAAA,CAAK,QAAQ,YAAe,GAAA,EAAE,QAAQ,IAAK,CAAA,IAAA,CAAK,QAAQ,CAAA;AAAA;AACjE,EAEA,MAAM,iBAAkB,OAAqD,EAAA;AAC3E,IAAA,MAAM,EAAE,GAAA,EAAK,GAAG,KAAA,EAAU,GAAA,OAAA;AAE1B,IAAI,IAAA,IAAA,CAAK,KAAK,KAAO,EAAA;AACnB,MAAC,IAAK,CAAA,IAAA,CAAK,KAAoB,CAAA,WAAA,CAAY,GAAG,CAAI,GAAA,KAAA;AAAA,KAC7C,MAAA;AACL,MAAK,IAAA,CAAA,IAAA,CAAK,QAAQ,EAAE,WAAA,EAAa,EAAE,CAAC,GAAG,GAAG,KAAA,EAAQ,EAAA;AAAA;AAEpD,IAAM,MAAA,IAAA,CAAK,QAAQ,aAAgB,GAAA;AAAA,MACjC,MAAA,EAAQ,KAAK,IAAK,CAAA,MAAA;AAAA,MAClB,KAAA,EAAO,KAAK,IAAK,CAAA;AAAA,KAClB,CAAA;AAAA;AACH,EAEA,MAAM,mBAAoB,OAA0C,EAAA;AAClE,IAAM,MAAA,IAAA,CAAK,gBAAiB,CAAA,kBAAA,CAAmB,OAAO,CAAA;AAAA;AACxD,EAEA,MAAM,cAAiC,GAAA;AACrC,IAAM,MAAA,IAAA,CAAK,iBAAiB,cAAe,EAAA;AAAA;AAC7C,EAEA,MAAM,QACJ,CAAA,MAAA,EACA,QACe,EAAA;AACf,IAAM,MAAA,IAAA,CAAK,QAAQ,YAAa,CAAA;AAAA,MAC9B,MAAA,EAAQ,KAAK,IAAK,CAAA,MAAA;AAAA,MAClB,MAAA,EAAQ,MAAW,KAAA,QAAA,GAAW,QAAW,GAAA,WAAA;AAAA,MACzC,SAAW,EAAA;AAAA,QACT,OAAA,EAAS,8BAA8B,MAAM,CAAA,CAAA;AAAA,QAC7C,GAAG;AAAA;AACL,KACD,CAAA;AACD,IAAA,IAAA,CAAK,MAAS,GAAA,IAAA;AACd,IAAA,IAAI,KAAK,kBAAoB,EAAA;AAC3B,MAAA,YAAA,CAAa,KAAK,kBAAkB,CAAA;AAAA;AACtC;AACF,EAEQ,YAAe,GAAA;AACrB,IAAK,IAAA,CAAA,kBAAA,GAAqB,WAAW,YAAY;AAC/C,MAAI,IAAA;AACF,QAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,aAAc,CAAA,IAAA,CAAK,KAAK,MAAM,CAAA;AACjD,QAAA,IAAA,CAAK,YAAa,EAAA;AAAA,eACX,KAAO,EAAA;AACd,QAAA,IAAA,CAAK,MAAS,GAAA,IAAA;AAEd,QAAA,IAAA,CAAK,MAAO,CAAA,KAAA;AAAA,UACV,CAAA,mBAAA,EAAsB,IAAK,CAAA,IAAA,CAAK,MAAM,CAAA,OAAA,CAAA;AAAA,UACtC;AAAA,SACF;AAAA;AACF,OACC,GAAI,CAAA;AAAA;AACT,EAEA,MAAM,uBAAyD,GAAA;AAC7D,IAAM,MAAA,OAAA,GAAU,KAAK,IAAK,CAAA,OAAA;AAE1B,IAAI,IAAA,OAAA,IAAW,QAAQ,sBAAwB,EAAA;AAC7C,MAAO,OAAA,IAAA,CAAK,KAAM,CAAA,OAAA,CAAQ,sBAAsB,CAAA;AAAA;AAElD,IAAI,IAAA,CAAC,KAAK,IAAM,EAAA;AACd,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA;AAEF,IAAO,OAAA,IAAA,CAAK,KAAK,kBAAmB,EAAA;AAAA;AAExC;AAkCO,MAAM,iBAAwC,CAAA;AAAA,EACnD,YACmB,OACA,EAAA,MAAA,EACA,MACA,EAAA,IAAA,EACA,8BAIA,OACjB,EAAA;AATiB,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AACA,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AACA,IAAA,IAAA,CAAA,4BAAA,GAAA,4BAAA;AAIA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AAAA;AAChB,EAEH,MAAM,KAAK,OAamD,EAAA;AAC5D,IAAI,IAAA,CAAC,IAAK,CAAA,OAAA,CAAQ,IAAM,EAAA;AACtB,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA;AAEF,IAAA,OAAO,MAAM,IAAK,CAAA,OAAA,CAAQ,IAAK,CAAA,OAAA,IAAW,EAAE,CAAA;AAAA;AAC9C,EAEQ,mBAAmBC,oBAAe,EAAA;AAAA,EAE1C,MAAc,mBACZ,CAAA,MAAA,EACA,eACA,EAAA;AACA,IAAA,IAAI,iBAAoB,GAAA,KAAA;AACxB,IAAM,MAAA,YAAA,GAAe,KAAK,MAAO,CAAA,EAAE,QAAQ,KAAO,EAAA,KAAA,CAAA,EAAW,CAAA,CAAE,SAAU,CAAA;AAAA,MACvE,OAAO,CAAK,CAAA,KAAA;AACV,QAAA,YAAA,CAAa,WAAY,EAAA;AAAA,OAC3B;AAAA,MACA,IAAM,EAAA,CAAC,EAAE,MAAA,EAAa,KAAA;AACpB,QAAA,KAAA,MAAW,SAAS,MAAQ,EAAA;AAC1B,UAAI,IAAA,KAAA,CAAM,SAAS,WAAa,EAAA;AAC9B,YAAA,eAAA,CAAgB,KAAM,EAAA;AACtB,YAAoB,iBAAA,GAAA,IAAA;AAAA;AAGtB,UAAA,IAAI,KAAM,CAAA,IAAA,KAAS,YAAgB,IAAA,CAAC,MAAM,iBAAmB,EAAA;AAC3D,YAAoB,iBAAA,GAAA,IAAA;AAAA;AACtB;AAEF,QAAA,IAAI,iBAAmB,EAAA;AACrB,UAAA,YAAA,CAAa,WAAY,EAAA;AAAA;AAC3B;AACF,KACD,CAAA;AAAA;AACH,EAEA,MAAa,YAA8B,GAAA;AACzC,IAAA,MAAM,OACJ,GAAA,IAAA,CAAK,MAAQ,EAAA,kBAAA,CAAmB,sCAAsC,CACtE,IAAA,KAAA;AAEF,IAAA,IAAI,OAAS,EAAA;AACX,MAAM,MAAA,cAAA,GAAiB,EAAE,OAAA,EAAS,EAAG,EAAA;AACrC,MAAA,MAAM,OAAU,GAAAC,mBAAA;AAAA,QACd,IAAK,CAAA,MAAA;AAAA,QACL,6CAAA;AAAA,QACA;AAAA,OACF;AACA,MAAA,MAAM,EAAE,GAAK,EAAA,gBAAA,KAAsB,MAAM,IAAA,CAAK,QAAQ,YAAe,GAAA;AAAA,QACnE;AAAA,OACD,CAAA,IAAM,EAAE,GAAA,EAAK,EAAG,EAAA;AACjB,MAAI,IAAA,gBAAA,CAAiB,SAAS,CAAG,EAAA;AAC/B,QAAA,IAAA,CAAK,cAAe,EAAA;AAAA;AACtB;AACF;AACF;AAAA;AAAA;AAAA,EAKA,MAAM,KAA8B,GAAA;AAClC,IAAS,WAAA;AACP,MAAA,MAAM,WAAc,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,SAAU,EAAA;AACjD,MAAA,IAAI,WAAa,EAAA;AACf,QAAM,MAAA,eAAA,GAAkB,IAAI,eAAgB,EAAA;AAC5C,QAAA,MAAM,IAAK,CAAA,mBAAA,CAAoB,WAAY,CAAA,EAAA,EAAI,eAAe,CAAA;AAC9D,QAAA,OAAO,WAAY,CAAA,MAAA;AAAA,UACjB;AAAA,YACE,QAAQ,WAAY,CAAA,EAAA;AAAA,YACpB,MAAM,WAAY,CAAA,IAAA;AAAA,YAClB,SAAS,WAAY,CAAA,OAAA;AAAA,YACrB,WAAW,WAAY,CAAA,SAAA;AAAA,YACvB,OAAO,WAAY,CAAA;AAAA,WACrB;AAAA,UACA,IAAK,CAAA,OAAA;AAAA,UACL,eAAgB,CAAA,MAAA;AAAA,UAChB,IAAK,CAAA,MAAA;AAAA,UACL,IAAK,CAAA,IAAA;AAAA,UACL,IAAK,CAAA,MAAA;AAAA,UACL,IAAK,CAAA;AAAA,SACP;AAAA;AAGF,MAAA,MAAM,KAAK,eAAgB,EAAA;AAAA;AAC7B;AACF;AAAA;AAAA;AAAA,EAKA,MAAM,SACJ,OAC6B,EAAA;AAC7B,IAAA,MAAM,OAAU,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,WAAW,OAAO,CAAA;AACrD,IAAA,IAAA,CAAK,cAAe,EAAA;AACpB,IAAO,OAAA;AAAA,MACL,QAAQ,OAAQ,CAAA;AAAA,KAClB;AAAA;AACF;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,MAAyC,EAAA;AACjD,IAAO,OAAA,IAAA,CAAK,OAAQ,CAAA,OAAA,CAAQ,MAAM,CAAA;AAAA;AACpC;AAAA;AAAA;AAAA,EAKA,OAAO,OAG2C,EAAA;AAChD,IAAO,OAAA,IAAIC,gCAAe,CAAY,QAAA,KAAA;AACpC,MAAM,MAAA,EAAE,QAAW,GAAA,OAAA;AAEnB,MAAA,IAAI,QAAQ,OAAQ,CAAA,KAAA;AACpB,MAAA,IAAI,SAAY,GAAA,KAAA;AAEhB,MAAA,CAAC,YAAY;AACX,QAAA,MAAM,IAAO,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,QAAQ,MAAM,CAAA;AAC9C,QAAA,MAAM,iBACJ,GAAA,IAAA,CAAK,IAAK,CAAA,qBAAA,EAAuB,qBACjC,KAAA,WAAA;AAEF,QAAA,OAAO,CAAC,SAAW,EAAA;AACjB,UAAA,MAAM,MAAS,GAAA,MAAM,IAAK,CAAA,OAAA,CAAQ,UAAW,CAAA;AAAA,YAC3C,iBAAA;AAAA,YACA,MAAA;AAAA,YACA;AAAA,WACD,CAAA;AACD,UAAM,MAAA,EAAE,QAAW,GAAA,MAAA;AACnB,UAAA,IAAI,OAAO,MAAQ,EAAA;AACjB,YAAA,KAAA,GAAQ,MAAO,CAAA,MAAA,CAAO,MAAS,GAAA,CAAC,CAAE,CAAA,EAAA;AAClC,YAAA,QAAA,CAAS,KAAK,MAAM,CAAA;AAAA;AAGtB,UAAA,MAAM,IAAI,OAAQ,CAAA,CAAA,OAAA,KAAW,UAAW,CAAA,OAAA,EAAS,GAAI,CAAC,CAAA;AAAA;AACxD,OACC,GAAA;AAEH,MAAA,OAAO,MAAM;AACX,QAAY,SAAA,GAAA,IAAA;AAAA,OACd;AAAA,KACD,CAAA;AAAA;AACH;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,OAA8C,EAAA;AAC9D,IAAA,MAAM,EAAE,KAAM,EAAA,GAAI,MAAM,IAAK,CAAA,OAAA,CAAQ,eAAe,OAAO,CAAA;AAC3D,IAAA,MAAM,OAAQ,CAAA,GAAA;AAAA,MACZ,KAAA,CAAM,GAAI,CAAA,OAAM,IAAQ,KAAA;AACtB,QAAA,MAAM,YAAe,GAAA,MAAM,IAAK,CAAA,OAAA,EAAS,WAAY,CAAA;AAAA,UACnD,OAAS,EAAA,MAAA;AAAA,UACT,aAAe,EAAA,QAAA;AAAA,UACf,IAAM,EAAA;AAAA,YACJ,UAAY,EAAA,cAAA;AAAA,YACZ,QAAQ,IAAK,CAAA;AAAA;AACf,SACD,CAAA;AACD,QAAI,IAAA;AACF,UAAM,MAAA,IAAA,CAAK,QAAQ,YAAa,CAAA;AAAA,YAC9B,QAAQ,IAAK,CAAA,MAAA;AAAA,YACb,MAAQ,EAAA,QAAA;AAAA,YACR,SAAW,EAAA;AAAA,cACT,OACE,EAAA;AAAA;AACJ,WACD,CAAA;AACD,UAAA,MAAM,cAAc,OAAQ,EAAA;AAAA,iBACrB,KAAO,EAAA;AACd,UAAA,IAAA,CAAK,OAAO,IAAK,CAAA,CAAA,uBAAA,EAA0B,KAAK,MAAM,CAAA,GAAA,EAAM,KAAK,CAAE,CAAA,CAAA;AACnE,UAAA,MAAM,YAAc,EAAA,IAAA,CAAK,EAAE,KAAA,EAAc,CAAA;AAAA;AAC3C,OACD;AAAA,KACH;AAAA;AACF,EAEQ,eAAkB,GAAA;AACxB,IAAA,OAAO,IAAK,CAAA,gBAAA;AAAA;AACd,EAEQ,cAAiB,GAAA;AACvB,IAAA,IAAA,CAAK,iBAAiB,OAAQ,EAAA;AAC9B,IAAA,IAAA,CAAK,mBAAmBF,oBAAe,EAAA;AAAA;AACzC,EAEA,MAAM,OAAO,MAAgB,EAAA;AAC3B,IAAM,MAAA,EAAE,QAAW,GAAA,MAAM,KAAK,OAAQ,CAAA,UAAA,CAAW,EAAE,MAAA,EAAQ,CAAA;AAC3D,IAAM,MAAA,aAAA,GACJ,MAAO,CAAA,MAAA,GAAS,CACZ,GAAA,MAAA,CACG,OAAO,CAAC,EAAE,IAAK,EAAA,KAAM,IAAM,EAAA,MAAM,EACjC,MAAO,CAAA,CAAC,IAAM,EAAA,IAAA,KAAU,IAAK,CAAA,EAAA,GAAK,IAAK,CAAA,EAAA,GAAK,IAAO,GAAA,IAAK,CAAE,CAAA,IAAA,CAC1D,MACH,GAAA,CAAA;AAEN,IAAM,MAAA,IAAA,CAAK,QAAQ,UAAa,GAAA;AAAA,MAC9B,MAAA;AAAA,MACA,IAAM,EAAA;AAAA,QACJ,OAAA,EAAS,QAAQ,aAAa,CAAA,oBAAA,CAAA;AAAA,QAC9B,MAAQ,EAAA,aAAA;AAAA,QACR,MAAQ,EAAA;AAAA;AACV,KACD,CAAA;AAAA;AACH,EAEA,MAAM,MAAO,OAGK,EAAA;AAChB,IAAM,MAAA,IAAA,CAAK,OAAQ,CAAA,SAAA,GAAY,OAAO,CAAA;AACtC,IAAA,IAAA,CAAK,cAAe,EAAA;AAAA;AAExB;;;;;"}
@@ -106,6 +106,7 @@ class TaskWorker {
106
106
  meta: {
107
107
  actionType: "execution",
108
108
  taskId: task.taskId,
109
+ createdBy: task.createdBy,
109
110
  taskParameters: task.spec.parameters,
110
111
  templateRef: task.spec.templateInfo?.entityRef
111
112
  }