Checkpoint

Signed-off-by: bnechyporenko <bnechyporenko@bol.com>
This commit is contained in:
bnechyporenko
2024-02-04 20:43:59 +01:00
parent 4be36f9f19
commit 245617991c
5 changed files with 58 additions and 15 deletions
@@ -26,7 +26,7 @@ import fs from 'fs-extra';
import path from 'path';
import nunjucks from 'nunjucks';
import { JsonArray, JsonObject, JsonValue } from '@backstage/types';
import { InputError, NotAllowedError } from '@backstage/errors';
import { InputError, NotAllowedError, stringifyError } from '@backstage/errors';
import { PassThrough } from 'stream';
import { generateExampleOutput, isTruthy } from './helper';
import { validate as validateJsonSchema } from 'jsonschema';
@@ -353,9 +353,22 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
key: string,
fn: () => Promise<U>,
) {
const value = await fn();
task.updateCheckpoint?.(key, value);
return value;
try {
const value = await fn();
task.updateCheckpoint?.({
key,
status: 'success',
value,
});
return value;
} catch (err) {
task.updateCheckpoint?.({
key,
status: 'failed',
reason: stringifyError(err),
});
throw err;
}
},
createTemporaryDirectory: async () => {
const tmpDir = await fs.mkdtemp(
@@ -16,7 +16,11 @@
import { Config } from '@backstage/config';
import { TaskSpec } from '@backstage/plugin-scaffolder-common';
import { TaskSecrets, TaskState } from '@backstage/plugin-scaffolder-node';
import {
TaskSecrets,
TaskState,
UpdateCheckpointOptions,
} from '@backstage/plugin-scaffolder-node';
import { JsonObject, Observable } from '@backstage/types';
import { Logger } from 'winston';
import ObservableImpl from 'zen-observable';
@@ -91,8 +95,12 @@ export class TaskManager implements TaskContext {
});
}
async updateCheckpoint?(key: string, value: JsonObject): Promise<void> {
this.task.state = { [key]: value };
async updateCheckpoint?(options: UpdateCheckpointOptions): Promise<void> {
if (this.task.state) {
this.task.state[options.key] = { ...options };
} else {
this.task.state = { [options.key]: options };
}
await this.storage.saveCheckpoint?.({
taskId: this.task.taskId,
state: this.task.state,
@@ -16,15 +16,11 @@
import { JsonObject } from '@backstage/types';
export type DefineCheckpointProps<U> = {
export const defineCheckpoint = async <U extends JsonObject>(props: {
checkpoint?: (key: string, fn: () => Promise<U>) => Promise<U>;
key: string;
fn: () => Promise<U>;
};
export const defineCheckpoint = async <U extends JsonObject>(
props: DefineCheckpointProps<U>,
): Promise<U> => {
}): Promise<U> => {
const { checkpoint, fn, key } = props;
return checkpoint
? checkpoint?.(key, async () => {
@@ -26,4 +26,5 @@ export type {
TaskEventType,
TaskState,
TaskStatus,
UpdateCheckpointOptions,
} from './types';
+27 -2
View File
@@ -31,7 +31,14 @@ export type TaskSecrets = Record<string, string> & {
*
* @public
*/
export type TaskState = Record<string, JsonObject>;
export type TaskState = {
[key: string]:
| { status: 'failed'; reason: string }
| {
status: 'success';
value: JsonObject;
};
};
/**
* The status of each step of the Task
@@ -108,6 +115,24 @@ export type TaskBrokerDispatchOptions = {
createdBy?: string;
};
/**
* The options passed to {@link TaskBroker.updateCheckpoint}
* Parameters to store the result of the executed checkpoint
*
* @public
*/
export type UpdateCheckpointOptions =
| {
key: string;
status: 'success';
value: JsonObject;
}
| {
key: string;
status: 'failed';
reason: string;
};
/**
* Task
*
@@ -126,7 +151,7 @@ export interface TaskContext {
emitLog(message: string, logMetadata?: JsonObject): Promise<void>;
updateCheckpoint?(key: string, value: JsonObject): Promise<void>;
updateCheckpoint?(options: UpdateCheckpointOptions): Promise<void>;
getWorkspaceName(): Promise<string>;
}