From 63a8d8e1710552caeb9e408baa53b48ad892ba81 Mon Sep 17 00:00:00 2001 From: Kashish Mittal Date: Fri, 25 Apr 2025 11:52:24 -0400 Subject: [PATCH] add a getTasks method to get multiple tasks through 1 DB query Signed-off-by: Kashish Mittal --- plugins/scaffolder-backend/report.api.md | 4 ++ .../src/scaffolder/tasks/DatabaseTaskStore.ts | 47 ++++++++++++++----- .../src/scaffolder/tasks/StorageTaskBroker.ts | 10 ++++ .../src/scaffolder/tasks/types.ts | 2 + .../scaffolder-backend/src/service/router.ts | 8 +--- plugins/scaffolder-node/report.api.md | 2 + plugins/scaffolder-node/src/tasks/types.ts | 2 + 7 files changed, 55 insertions(+), 20 deletions(-) diff --git a/plugins/scaffolder-backend/report.api.md b/plugins/scaffolder-backend/report.api.md index e22a7d1370..cc7d83c7e1 100644 --- a/plugins/scaffolder-backend/report.api.md +++ b/plugins/scaffolder-backend/report.api.md @@ -329,6 +329,8 @@ export class DatabaseTaskStore implements TaskStore { // (undocumented) getTask(taskId: string): Promise; // (undocumented) + getTasks(taskIds: string[]): Promise; + // (undocumented) getTaskState({ taskId }: { taskId: string }): Promise< | { state: JsonObject; @@ -483,6 +485,8 @@ export interface TaskStore { // (undocumented) getTask(taskId: string): Promise; // (undocumented) + getTasks(taskIds: string[]): Promise; + // (undocumented) getTaskState?({ taskId }: { taskId: string }): Promise< | { state: JsonObject; diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts index 795a4b7ff6..fc866996b5 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts @@ -344,24 +344,45 @@ export class DatabaseTaskStore implements TaskStore { throw new NotFoundError(`No task with id '${taskId}' found`); } try { - const spec = JSON.parse(result.spec); - const secrets = result.secrets ? JSON.parse(result.secrets) : undefined; - const state = this.getState(result); - return { - id: result.id, - spec, - status: result.status, - lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at), - createdAt: parseSqlDateToIsoString(result.created_at), - createdBy: result.created_by ?? undefined, - secrets, - state, - }; + return this.parseTaskRow(result); } catch (error) { throw new Error(`Failed to parse spec of task '${taskId}', ${error}`); } } + async getTasks(taskIds: string[]): Promise { + const results = await this.db('tasks') + .whereIn('id', taskIds) + .select(); + + return results.map(result => { + try { + return this.parseTaskRow(result); + } catch (error) { + throw new Error( + `Failed to parse spec of task '${result.id}', ${error}`, + ); + } + }); + } + + private parseTaskRow(result: RawDbTaskRow): SerializedTask { + const spec = JSON.parse(result.spec); + const secrets = result.secrets ? JSON.parse(result.secrets) : undefined; + const state = this.getState(result); + + return { + id: result.id, + spec, + status: result.status, + lastHeartbeatAt: parseSqlDateToIsoString(result.last_heartbeat_at), + createdAt: parseSqlDateToIsoString(result.created_at), + createdBy: result.created_by ?? undefined, + secrets, + state, + }; + } + async createTask( options: TaskStoreCreateTaskOptions, ): Promise { diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts index 86f9f7fcf7..4d3c9414aa 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/StorageTaskBroker.ts @@ -29,6 +29,7 @@ import { TaskBrokerDispatchOptions, TaskCompletionState, TaskContext, + TaskFilters, TaskSecrets, TaskStatus, } from '@backstage/plugin-scaffolder-node'; @@ -43,6 +44,7 @@ import ObservableImpl from 'zen-observable'; import { DefaultWorkspaceService, WorkspaceService } from './WorkspaceService'; import { readDuration } from './helper'; import { InternalTaskSecrets, TaskStore } from './types'; +import { PermissionCriteria } from '@backstage/plugin-permission-common'; type TaskState = { checkpoints: { @@ -291,6 +293,7 @@ export class StorageTaskBroker implements TaskBroker { offset?: number; }; order?: { order: 'asc' | 'desc'; field: string }[]; + permissionFilters?: PermissionCriteria; }): Promise<{ tasks: SerializedTask[]; totalTasks?: number }> { if (!this.storage.list) { throw new Error( @@ -400,6 +403,13 @@ export class StorageTaskBroker implements TaskBroker { return this.storage.getTask(taskId); } + /** + * {@inheritdoc TaskBroker.getTasks} + */ + getTasks(taskIds: string[]): Promise { + return this.storage.getTasks(taskIds); + } + /** * {@inheritdoc TaskBroker.event$} */ diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts index 62ffb171ff..f9d10ddb0f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/types.ts @@ -110,6 +110,8 @@ export interface TaskStore { getTask(taskId: string): Promise; + getTasks(taskIds: string[]): Promise; + claimTask(): Promise; completeTask(options: { diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 291fcbdae1..ba476ae25f 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -366,13 +366,7 @@ export async function createRouter( resourceType: RESOURCE_TYPE_SCAFFOLDER_TASK, permissions: scaffolderTaskPermissions, rules: taskRules, - getResources: async resourceRefs => { - return Promise.all( - resourceRefs.map(async taskId => { - return await taskBroker.get(taskId); - }), - ); - }, + getResources: resourceRefs => taskBroker.getTasks(resourceRefs), }, ], permissions: scaffolderPermissions, diff --git a/plugins/scaffolder-node/report.api.md b/plugins/scaffolder-node/report.api.md index 09829d2723..ba8263cf62 100644 --- a/plugins/scaffolder-node/report.api.md +++ b/plugins/scaffolder-node/report.api.md @@ -361,6 +361,8 @@ export interface TaskBroker { // (undocumented) get(taskId: string): Promise; // (undocumented) + getTasks(taskIds: string[]): Promise; + // (undocumented) list?(options?: { filters?: { createdBy?: string | string[]; diff --git a/plugins/scaffolder-node/src/tasks/types.ts b/plugins/scaffolder-node/src/tasks/types.ts index 53169e3432..c15832645d 100644 --- a/plugins/scaffolder-node/src/tasks/types.ts +++ b/plugins/scaffolder-node/src/tasks/types.ts @@ -204,6 +204,8 @@ export interface TaskBroker { get(taskId: string): Promise; + getTasks(taskIds: string[]): Promise; + list?(options?: { filters?: { createdBy?: string | string[];