From 1f9f8f88479cd60039dab3ee86f9ef224e0e0543 Mon Sep 17 00:00:00 2001 From: Travis Kuhl Date: Tue, 29 Oct 2024 16:53:14 -0700 Subject: [PATCH] ping reporter --- bin/run.ts | 1 + deno.json | 6 +++- src/cli/ffr/execute.ts | 17 +++++++--- src/cli/ffr/watch.ts | 2 ++ src/constants.ts | 1 + src/launch/worker.ts | 2 +- src/reporters/create.ts | 4 +++ src/reporters/ping.ts | 68 +++++++++++++++++++++++++++++++++++++++ src/reporters/supabase.ts | 7 ++-- src/runtime/execution.ts | 4 +-- src/runtime/state.ts | 3 +- src/runtime/step.ts | 8 +++-- src/schema/job.ts | 2 ++ src/schema/launch.ts | 2 ++ src/schema/scalar.ts | 2 ++ src/schema/step.ts | 2 ++ src/schema/workflow.ts | 2 ++ src/types.ts | 25 ++++++++------ 18 files changed, 132 insertions(+), 26 deletions(-) create mode 100644 src/reporters/ping.ts diff --git a/bin/run.ts b/bin/run.ts index a98c34f..1e29e15 100644 --- a/bin/run.ts +++ b/bin/run.ts @@ -31,4 +31,5 @@ await main({ verbose, reportFile: report, remoteUrl, + include: [], }); diff --git a/deno.json b/deno.json index b4def23..2463911 100644 --- a/deno.json +++ b/deno.json @@ -25,7 +25,7 @@ "ffr": "deno run -A --unstable-worker-options ./bin/ffr.ts" }, "exclude": [ - "./www" + "./www" ], "compilerOptions": { "strict": true, @@ -34,6 +34,10 @@ "noUncheckedIndexedAccess": true }, "lint": { + "include": [ + "src/**/*.ts", + "!src/schema/*.ts" + ], "exclude": [ "tmp*" ] diff --git a/src/cli/ffr/execute.ts b/src/cli/ffr/execute.ts index 73ecc58..bc3c22b 100644 --- a/src/cli/ffr/execute.ts +++ b/src/cli/ffr/execute.ts @@ -70,6 +70,12 @@ export default async function main(ctx: FFrCliContext) { const foundFiles: Array<{ name: string; size: number }> = []; + const spin = new Spinner({ + message: "Building run manifest...", + }); + + spin.start(); + // make sure all of the files exist // if there are any missing files, push // them to the missing array so we can @@ -87,6 +93,7 @@ export default async function main(ctx: FFrCliContext) { size: f.size, }); } catch (_) { + spin.stop(); const value = await confirm( `Unable to open file "${inputPath}" (${p}). Would you like to ignore this file?`, { @@ -99,9 +106,13 @@ export default async function main(ctx: FFrCliContext) { Deno.exit(1); } foundFiles.push({ name: inputPath, size: 0 }); + } finally { + spin.start(); } } + spin.message = "Sending build manifest for compilation..."; + // we need to get sts federated token // that is tied to this user's storage bucket // we'll also let them know what files are @@ -123,11 +134,7 @@ export default async function main(ctx: FFrCliContext) { assert(response.config, "Missing response config"); - const spin = new Spinner({ - message: "Preparing to upload files...", - }); - - spin.start(); + spin.message = "Preparing to upload files..."; try { // create our sts client diff --git a/src/cli/ffr/watch.ts b/src/cli/ffr/watch.ts index 1513c6b..9b539d3 100644 --- a/src/cli/ffr/watch.ts +++ b/src/cli/ffr/watch.ts @@ -49,6 +49,8 @@ export default async function main(ctx: FFrCliContext) { let spin: Spinner | undefined; + console.log(status); + if (status === "pending") { spin = new Spinner({ message: "Waiting for worker initialization...", diff --git a/src/constants.ts b/src/constants.ts index bc3f69a..603979b 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -35,6 +35,7 @@ export enum ReporterName { Console = "console", File = "file", Supabase = "supabase", + Ping = "ping", } export enum LaunchMode { diff --git a/src/launch/worker.ts b/src/launch/worker.ts index d66c0f3..b4f662a 100644 --- a/src/launch/worker.ts +++ b/src/launch/worker.ts @@ -10,7 +10,7 @@ import { evaluateExpression, isExpressionResultTruthy, } from "../libs/expression/expression.ts"; -import { LaunchWorkerOptions } from "../types.ts"; +import type { LaunchWorkerOptions } from "../types.ts"; type PossibleConfigurationFormat = { format: "yaml"; diff --git a/src/reporters/create.ts b/src/reporters/create.ts index 3802081..4bf2d97 100644 --- a/src/reporters/create.ts +++ b/src/reporters/create.ts @@ -4,6 +4,7 @@ import { ReporterName } from "../constants.ts"; import { FileReporter } from "./file.ts"; import { SupabaseReporter } from "./supabase.ts"; import { ConsoleReporter } from "./console.ts"; +import { PingReporter } from "./ping.ts"; export function createReporter( name: string, @@ -18,6 +19,9 @@ export function createReporter( case ReporterName.Console: return new ConsoleReporter(); + case ReporterName.Ping: + return new PingReporter(); + default: { throw new Error(`Unknown reporter: ${name}`); } diff --git a/src/reporters/ping.ts b/src/reporters/ping.ts new file mode 100644 index 0000000..205a444 --- /dev/null +++ b/src/reporters/ping.ts @@ -0,0 +1,68 @@ +import { AbstractReporter } from "./abstract.ts"; +import type { ReporterChangeData, Workflow } from "../types.ts"; +import { assert } from "../deps.ts"; + +export interface PingReporterOptions { + url: string; + interval?: number; +} + +export class PingReporter extends AbstractReporter { + #lock = false; + #pingInterval: number | null = null; + + override setOptions(options: PingReporterOptions) { + super.setOptions(options); + + assert(options.url, "Ping URL is required for PingReporter"); + + this._startPingInterval(); + } + + override async destroy() { + await Promise.resolve(() => this._stopPingInterval()); + } + + _startPingInterval() { + this._stopPingInterval(); + this.#pingInterval = setInterval(() => { + this._ping(); + }, 1000 * (this.options.interval ?? 60)); + } + + _stopPingInterval() { + this.#pingInterval && clearInterval(this.#pingInterval); + } + + async execute() { + } + + async report( + _report: Workflow.Report, + _configuration?: Workflow.Configuration, + ): Promise { + } + + async change(_type: string, _data: ReporterChangeData): Promise { + } + + async _ping(): Promise { + if (this.#lock) { + return; + } + + try { + await fetch(this.options.url, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(new Date().getTime().toString()), + }); + } catch (error) { + console.error("Error pinging", error); + } finally { + this.#lock = false; + } + } +} diff --git a/src/reporters/supabase.ts b/src/reporters/supabase.ts index bbdc02a..4785302 100644 --- a/src/reporters/supabase.ts +++ b/src/reporters/supabase.ts @@ -13,6 +13,7 @@ export interface SupabaseReporterOptions { url: string; anon_key: string; service_key: string; + interval?: number; } type Client = supabase.SupabaseClient; @@ -62,9 +63,7 @@ export class SupabaseReporter }, }); - this.#changeQueueInterval = setInterval(() => { - this._flush(); - }, 1000 * 60 * 1); + this._startChangeQueue(); } override async destroy() { @@ -76,7 +75,7 @@ export class SupabaseReporter this._stopChangeQueue(); this.#changeQueueInterval = setInterval(() => { this._flush(); - }, 1000 * 60 * 1); + }, 1000 * (this.options.interval ?? 30)); } _stopChangeQueue() { diff --git a/src/runtime/execution.ts b/src/runtime/execution.ts index 2739299..4776f66 100644 --- a/src/runtime/execution.ts +++ b/src/runtime/execution.ts @@ -1,6 +1,6 @@ import { assert, dirname } from "../deps.ts"; -import { Manager } from "./manager.ts"; +import type { Manager } from "./manager.ts"; import type { JsonObject, ReporterChangeData, Workflow } from "../types.ts"; import { Job } from "./job.ts"; import { executeDenoCommand } from "../libs/deno/execute.ts"; @@ -10,7 +10,7 @@ import { executeDenoRun, type ExecuteDenoRunOptions, } from "../libs/deno/execute.ts"; -import { Folder } from "./folder.ts"; +import type { Folder } from "./folder.ts"; import { RunnerResult, StateName } from "../constants.ts"; import { evaluateWhen } from "../libs/expression/when.ts"; import { asError } from "../libs/utils.ts"; diff --git a/src/runtime/state.ts b/src/runtime/state.ts index 478a5fc..1a1b199 100644 --- a/src/runtime/state.ts +++ b/src/runtime/state.ts @@ -1,6 +1,7 @@ // deno-lint-ignore-file require-await import { RunnerResult, RunnerStatus, StateName } from "../constants.ts"; import type { + CombinedRuntimeState, ReporterChangeData, Result, RuntimeState, @@ -64,7 +65,7 @@ export abstract class State implements RuntimeState { return this._data[name] ?? defaultValue; } - getCombinedState() { + getCombinedState(): CombinedRuntimeState { return { id: this.id, name: this.name, diff --git a/src/runtime/step.ts b/src/runtime/step.ts index 4955bf4..cf55241 100644 --- a/src/runtime/step.ts +++ b/src/runtime/step.ts @@ -1,5 +1,9 @@ import type { Job } from "./job.ts"; -import type { ReporterChangeData, Workflow } from "../types.ts"; +import type { + CombinedRuntimeState, + ReporterChangeData, + Workflow, +} from "../types.ts"; import { resolveActionUrlForDenoCommand, resolveActionUrlFromDefinition, @@ -48,7 +52,7 @@ export class Step extends State { return this.job.logger; } - override getCombinedState() { + override getCombinedState(): CombinedRuntimeState { return { ...super.getCombinedState(), definition: this.def, diff --git a/src/schema/job.ts b/src/schema/job.ts index 6db12be..6b14740 100644 --- a/src/schema/job.ts +++ b/src/schema/job.ts @@ -1,3 +1,5 @@ +// deno-lint-ignore-file + import { z } from "../deps.ts"; import { Description, Label, Name, When } from "./scalar.ts"; diff --git a/src/schema/launch.ts b/src/schema/launch.ts index 027f4cd..19a9fe1 100644 --- a/src/schema/launch.ts +++ b/src/schema/launch.ts @@ -1,3 +1,5 @@ +// deno-lint-ignore-file + import { z } from "../deps.ts"; import { WorkflowSchema } from "./workflow.ts"; diff --git a/src/schema/scalar.ts b/src/schema/scalar.ts index 2af1d82..2006e3c 100644 --- a/src/schema/scalar.ts +++ b/src/schema/scalar.ts @@ -1,3 +1,5 @@ +// deno-lint-ignore-file + import { z } from "../deps.ts"; /** diff --git a/src/schema/step.ts b/src/schema/step.ts index 388cfe1..399cc42 100644 --- a/src/schema/step.ts +++ b/src/schema/step.ts @@ -1,3 +1,5 @@ +// deno-lint-ignore-file + import { z } from "../deps.ts"; import { diff --git a/src/schema/workflow.ts b/src/schema/workflow.ts index 3b31623..9cc800e 100644 --- a/src/schema/workflow.ts +++ b/src/schema/workflow.ts @@ -1,3 +1,5 @@ +// deno-lint-ignore-file + import { z } from "../deps.ts"; import { JobSchema } from "./job.ts"; import { diff --git a/src/types.ts b/src/types.ts index e0fa9ac..44a66a2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,15 +1,15 @@ // deno-lint-ignore-file no-namespace -import { z } from "./deps.ts"; -import { type WorkflowSchema } from "./schema/workflow.ts"; -import { type JobSchema } from "./schema/job.ts"; -import { - type ExecuteSchema, - type ExecuteWithWorkflowFileSchema, - type ExecuteWithWorkflowSchema, - type LaunchSchema, - type ServerSchema, - type WorkerSchema, +import type { z } from "./deps.ts"; +import type { WorkflowSchema } from "./schema/workflow.ts"; +import type { JobSchema } from "./schema/job.ts"; +import type { + ExecuteSchema, + ExecuteWithWorkflowFileSchema, + ExecuteWithWorkflowSchema, + LaunchSchema, + ServerSchema, + WorkerSchema, } from "./schema/launch.ts"; import type * as step from "./schema/step.ts"; import type * as scalar from "./schema/scalar.ts"; @@ -51,6 +51,11 @@ export interface RuntimeState { }; } +export type CombinedRuntimeState = RuntimeState["state"] & { + id: string; + name: string; +}; + export namespace Workflow { export type Configuration = z.infer;