diff --git a/apps/event-worker/src/target-scan/index.ts b/apps/event-worker/src/target-scan/index.ts index 83bdcdc7..86ab4a58 100644 --- a/apps/event-worker/src/target-scan/index.ts +++ b/apps/event-worker/src/target-scan/index.ts @@ -1,6 +1,5 @@ import type { TargetScanEvent } from "@ctrlplane/validators/events"; -import { Queue, Worker } from "bullmq"; -import ms from "ms"; +import { Job, Queue, Worker } from "bullmq"; import { eq, takeFirstOrNull } from "@ctrlplane/db"; import { db } from "@ctrlplane/db/client"; @@ -17,8 +16,10 @@ import { getGkeTargets } from "./gke.js"; import { upsertTargets } from "./upsert.js"; const targetScanQueue = new Queue(Channel.TargetScan, { connection: redis }); -const requeue = (data: any, delay: number) => - targetScanQueue.add(Channel.TargetScan, data, { delay }); +const removeTargetJob = (job: Job) => + job.repeatJobKey != null + ? targetScanQueue.removeRepeatableByKey(job.repeatJobKey) + : null; export const createTargetScanWorker = () => new Worker( @@ -36,7 +37,11 @@ export const createTargetScanWorker = () => eq(targetProvider.id, targetProviderGoogle.targetProviderId), ) .then(takeFirstOrNull); - if (tp == null) return; + + if (tp == null) { + await removeTargetJob(job); + return; + } logger.info( `Received scanning request for "${tp.target_provider.name}" (${targetProviderId}).`, @@ -51,9 +56,10 @@ export const createTargetScanWorker = () => await upsertTargets(db, tp.workspace.id, gkeTargets); } - - await requeue(job.data, ms("5m")); - // }, - { connection: redis, concurrency: 10 }, + { + connection: redis, + removeOnComplete: { age: 0, count: 0 }, + concurrency: 10, + }, ); diff --git a/apps/target-provider/README.md b/apps/target-provider/README.md deleted file mode 100644 index cedca48d..00000000 --- a/apps/target-provider/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Rollout Job - -Job that checks if releases are ready for rollout diff --git a/apps/target-provider/eslint.config.js b/apps/target-provider/eslint.config.js deleted file mode 100644 index dba3e699..00000000 --- a/apps/target-provider/eslint.config.js +++ /dev/null @@ -1,9 +0,0 @@ -import baseConfig from "@ctrlplane/eslint-config/base"; - -/** @type {import('typescript-eslint').Config} */ -export default [ - { - ignores: [".nitro/**", ".output/**"], - }, - ...baseConfig, -]; diff --git a/apps/target-provider/package.json b/apps/target-provider/package.json deleted file mode 100644 index 779a9c03..00000000 --- a/apps/target-provider/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "@ctrlplane/target-provider", - "private": true, - "type": "module", - "scripts": { - "clean": "rm -rf .turbo node_modules", - "dev": "pnpm with-env tsx watch --clear-screen=false src/index.ts", - "lint": "eslint", - "format": "prettier --check . --ignore-path ../../.gitignore", - "typecheck": "tsc --noEmit", - "with-env": "dotenv -e ../../.env --" - }, - "dependencies": { - "@ctrlplane/db": "workspace:*", - "@google-cloud/container": "^5.16.0", - "@kubernetes/client-node": "^0.21.0", - "@t3-oss/env-core": "^0.10.1", - "cron": "^3.1.7", - "dotenv": "^16.4.5", - "google-auth-library": "^9.13.0", - "semver": "^7.6.2", - "zod": "catalog:" - }, - "devDependencies": { - "@ctrlplane/eslint-config": "workspace:^", - "@ctrlplane/prettier-config": "workspace:^", - "@ctrlplane/tsconfig": "workspace:*", - "eslint": "catalog:", - "prettier": "catalog:", - "tsx": "^4.11.0", - "typescript": "^5.4.5" - }, - "prettier": "@ctrlplane/prettier-config" -} diff --git a/apps/target-provider/src/config.ts b/apps/target-provider/src/config.ts deleted file mode 100644 index c19091b2..00000000 --- a/apps/target-provider/src/config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createEnv } from "@t3-oss/env-core"; -import dotenv from "dotenv"; -import { z } from "zod"; - -dotenv.config(); - -export const env = createEnv({ - server: { POSTGRES_URL: z.string().url() }, - runtimeEnv: process.env, -}); diff --git a/apps/target-provider/src/google.ts b/apps/target-provider/src/google.ts deleted file mode 100644 index 27a7f232..00000000 --- a/apps/target-provider/src/google.ts +++ /dev/null @@ -1,215 +0,0 @@ -import type { TargetProviderGoogle } from "@ctrlplane/db/schema"; -import type { ClusterManagerClient } from "@google-cloud/container"; -import type { google } from "@google-cloud/container/build/protos/protos"; -import Container from "@google-cloud/container"; -import { CoreV1Api, KubeConfig } from "@kubernetes/client-node"; -import { GoogleAuth } from "google-auth-library"; -import _ from "lodash"; -import { SemVer } from "semver"; - -import type { UpsertTarget } from "./utils"; -import { omitNullUndefined } from "./utils"; - -const sourceCredentials = new GoogleAuth({ - scopes: ["https://www.googleapis.com/auth/cloud-platform"], -}); - -const getGoogleClusterClient = async (targetPrincipal?: string | null) => { - return new Container.v1.ClusterManagerClient({ - clientOptions: - targetPrincipal != null - ? { - sourceClient: await sourceCredentials.getClient(), - targetPrincipal, - lifetime: 3600, // Token lifetime in seconds - delegates: [], - targetScopes: ["https://www.googleapis.com/auth/cloud-platform"], - } - : {}, - }); -}; - -const getClusters = async ( - clusterClient: ClusterManagerClient, - projectId: string, -) => { - const request = { parent: `projects/${projectId}/locations/-` }; - const [response] = await clusterClient.listClusters(request); - const { clusters } = response; - return clusters ?? []; -}; - -const connectToCluster = async ( - clusterClient: ClusterManagerClient, - project: string, - clusterName: string, - clusterLocation: string, -) => { - const [credentials] = await clusterClient.getCluster({ - name: `projects/${project}/locations/${clusterLocation}/clusters/${clusterName}`, - }); - const kubeConfig = new KubeConfig(); - kubeConfig.loadFromOptions({ - clusters: [ - { - name: clusterName, - server: `https://${credentials.endpoint}`, - caData: credentials.masterAuth!.clusterCaCertificate!, - }, - ], - users: [ - { - name: clusterName, - token: (await sourceCredentials.getAccessToken())!, - }, - ], - contexts: [ - { - name: clusterName, - user: clusterName, - cluster: clusterName, - }, - ], - currentContext: clusterName, - }); - return kubeConfig; -}; - -const clusterToTarget = ( - workspaceId: string, - providerId: string, - project: string, - cluster: google.container.v1.ICluster, -) => { - const masterVersion = new SemVer(cluster.currentMasterVersion ?? "0"); - const nodeVersion = new SemVer(cluster.currentNodeVersion ?? "0"); - const autoscaling = String( - cluster.autoscaling?.enableNodeAutoprovisioning ?? false, - ); - - const appUrl = `https://console.cloud.google.com/kubernetes/clusters/details/${cluster.location}/${cluster.name}/details?project=${project}`; - return { - workspaceId, - name: cluster.name ?? cluster.id ?? "", - providerId, - identifier: `${project}/${cluster.name}`, - version: "kubernetes/v1", - kind: "KubernetesAPI", - config: { - name: cluster.name, - status: cluster.status, - cluster: { - certificateAuthorityData: cluster.masterAuth?.clusterCaCertificate, - endpoint: `https://${cluster.endpoint}`, - }, - }, - labels: omitNullUndefined({ - "ctrlplane/url": appUrl, - - "google/self-link": cluster.selfLink, - "google/project": project, - "google/location": cluster.location, - "google/autopilot": cluster.autopilot?.enabled, - - "kubernetes/cluster-name": cluster.name, - "kubernetes/cluster-id": cluster.id, - "kubernetes/distribution": "gke", - "kubernetes/status": cluster.status, - "kubernetes/node-count": String(cluster.currentNodeCount ?? "unknown"), - - "kubernetes/master-version": masterVersion.version, - "kubernetes/master-version-major": String(masterVersion.major), - "kubernetes/master-version-minor": String(masterVersion.minor), - "kubernetes/master-version-patch": String(masterVersion.patch), - - "kubernetes/node-version": nodeVersion.version, - "kubernetes/node-version-major": String(nodeVersion.major), - "kubernetes/node-version-minor": String(nodeVersion.minor), - "kubernetes/node-version-patch": String(nodeVersion.patch), - - "kubernetes/autoscaling-enabled": autoscaling, - - ...(cluster.resourceLabels ?? {}), - }), - }; -}; - -export const getGkeTargets = async ( - workspaceId: string, - config: TargetProviderGoogle, - serviceAccountEmail: string | null, -) => { - const googleClusterClient = await getGoogleClusterClient(serviceAccountEmail); - - const clusters = ( - await Promise.allSettled( - config.projectIds.map(async (project) => { - const clusters = await getClusters(googleClusterClient, project); - return { project, clusters }; - }), - ) - ) - .filter((result) => result.status === "fulfilled") - .map((v) => v.value); - - const kubernetesApiTargets: UpsertTarget[] = clusters - .map(({ project, clusters }) => - clusters.map((cluster) => - clusterToTarget(workspaceId, config.targetProviderId, project, cluster), - ), - ) - .flat(); - - const kubernetesNamespaceTargets = ( - await Promise.all( - clusters.flatMap(({ project, clusters }) => { - return clusters.flatMap(async (cluster) => { - if (cluster.name == null || cluster.location == null) return []; - const kubeConfig = await connectToCluster( - googleClusterClient, - project, - cluster.name, - cluster.location, - ); - - const k8sApi = kubeConfig.makeApiClient(CoreV1Api); - try { - const response = await k8sApi.listNamespace(); - const namespaces = response.body.items; - return namespaces - .filter((n) => n.metadata != null) - .map((n) => - _.merge( - clusterToTarget( - workspaceId, - config.targetProviderId, - project, - cluster, - ), - { - name: `${cluster.name ?? cluster.id ?? ""}/${n.metadata!.name}`, - kind: "KubernetesNamespace", - identifier: `${project}/${cluster.name}/${n.metadata!.name}`, - config: { - namespace: n.metadata!.name, - }, - labels: { - ...n.metadata?.labels, - "kubernetes/namespace": n.metadata!.name, - }, - }, - ), - ); - } catch { - console.log( - `Unable to connect to cluster: ${cluster.name}/${cluster.id}`, - ); - return []; - } - }); - }), - ) - ).flat(); - - return [...kubernetesApiTargets, ...kubernetesNamespaceTargets]; -}; diff --git a/apps/target-provider/src/index.ts b/apps/target-provider/src/index.ts deleted file mode 100644 index 6e1552de..00000000 --- a/apps/target-provider/src/index.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { CronJob } from "cron"; - -import { eq } from "@ctrlplane/db"; -import { db } from "@ctrlplane/db/client"; -import { - targetProvider, - targetProviderGoogle, - workspace, -} from "@ctrlplane/db/schema"; - -import { getGkeTargets } from "./google"; -import { upsertTargets } from "./targets"; - -const run = async () => { - console.log("Running managed providers"); - - const googleProviders = await db - .select() - .from(targetProvider) - .innerJoin(workspace, eq(targetProvider.workspaceId, workspace.id)) - .innerJoin( - targetProviderGoogle, - eq(targetProvider.id, targetProviderGoogle.targetProviderId), - ); - - for (const provider of googleProviders) { - console.log("Syncing provider", provider.target_provider.name); - const targets = await getGkeTargets( - provider.target_provider.workspaceId, - provider.target_provider_google, - provider.workspace.googleServiceAccountEmail, - ); - await upsertTargets(db, provider.workspace.id, targets); - } -}; - -const job = new CronJob("* * * * *", run); - -console.log("Starting managed providers cronjob"); -run(); -job.start(); diff --git a/apps/target-provider/src/targets.ts b/apps/target-provider/src/targets.ts deleted file mode 100644 index 83f79d18..00000000 --- a/apps/target-provider/src/targets.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { Tx } from "@ctrlplane/db"; - -import { buildConflictUpdateColumns, sql } from "@ctrlplane/db"; -import { target } from "@ctrlplane/db/schema"; - -import type { UpsertTarget } from "./utils"; - -export const upsertTargets = (db: Tx, providerId: string, ts: UpsertTarget[]) => - db - .insert(target) - .values(ts) - .onConflictDoUpdate({ - target: [target.identifier, target.workspaceId], - setWhere: sql`target.provider_id = ${providerId}`, - set: buildConflictUpdateColumns(target, ["labels"]), - }) - .returning(); diff --git a/apps/target-provider/src/utils.ts b/apps/target-provider/src/utils.ts deleted file mode 100644 index 194c28bd..00000000 --- a/apps/target-provider/src/utils.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Target } from "@ctrlplane/db/schema"; - -export function omitNullUndefined(obj: object) { - return Object.entries(obj).reduce>( - (acc, [key, value]) => { - if (value !== null && value !== undefined) acc[key] = value; - return acc; - }, - {}, - ); -} - -export type UpsertTarget = Pick< - Target, - | "version" - | "name" - | "kind" - | "config" - | "labels" - | "providerId" - | "identifier" - | "workspaceId" ->; diff --git a/apps/target-provider/tsconfig.json b/apps/target-provider/tsconfig.json deleted file mode 100644 index ef186d5c..00000000 --- a/apps/target-provider/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "@ctrlplane/tsconfig/base.json", - "compilerOptions": { - "target": "ESNext", - "outDir": "dist", - "noEmit": false, - "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json", - "baseUrl": ".", - "paths": { - "@/*": ["src/*"] - }, - "esModuleInterop": true, - "importsNotUsedAsValues": "remove" - }, - "include": ["src", "*.ts"], - "exclude": ["node_modules"] -} diff --git a/packages/api/package.json b/packages/api/package.json index 6bce69ab..70fb15ed 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -26,12 +26,15 @@ "@octokit/auth-app": "^7.1.0", "@octokit/rest": "^20.1.1", "@octokit/types": "^13.5.0", - "js-yaml": "^4.1.0", "@t3-oss/env-core": "^0.10.1", "@trpc/server": "11.0.0-rc.364", + "bullmq": "^5.12.10", "google-auth-library": "^9.13.0", "googleapis": "^140.0.1", + "ioredis": "^5.4.1", + "js-yaml": "^4.1.0", "lodash": "^4.17.21", + "ms": "^2.1.3", "superjson": "2.2.1", "ts-is-present": "^1.2.2", "zod": "catalog:" @@ -41,10 +44,10 @@ "@ctrlplane/prettier-config": "workspace:*", "@ctrlplane/tsconfig": "workspace:*", "@octokit/types": "^13.5.0", + "@types/js-yaml": "^4.0.9", "@types/lodash": "^4.17.5", "@types/pg": "^8.11.6", "@types/semver": "^7.5.8", - "@types/js-yaml": "^4.0.9", "eslint": "catalog:", "prettier": "catalog:", "typescript": "^5.4.5" diff --git a/packages/api/src/config.ts b/packages/api/src/config.ts index 7eaa64b8..c0cb263f 100644 --- a/packages/api/src/config.ts +++ b/packages/api/src/config.ts @@ -3,12 +3,22 @@ import { z } from "zod"; export const env = createEnv({ server: { + REDIS_URL: z.string(), + GITHUB_BOT_PRIVATE_KEY: z.string().optional(), GITHUB_BOT_CLIENT_ID: z.string().optional(), GITHUB_BOT_CLIENT_SECRET: z.string().optional(), GITHUB_BOT_APP_ID: z.string().optional(), - WORKSPACE_CREATE_GOOGLE_SERVICE_ACCOUNTS: z.boolean().default(false), + WORKSPACE_CREATE_GOOGLE_SERVICE_ACCOUNTS: z + .enum(["true", "false"]) + .default("false") + .transform((value) => value === "true"), }, runtimeEnv: process.env, + emptyStringAsUndefined: true, + skipValidation: + !!process.env.CI || + !!process.env.SKIP_ENV_VALIDATION || + process.env.npm_lifecycle_event === "lint", }); diff --git a/packages/api/src/dispatch.ts b/packages/api/src/dispatch.ts new file mode 100644 index 00000000..2489a153 --- /dev/null +++ b/packages/api/src/dispatch.ts @@ -0,0 +1,12 @@ +import { Queue } from "bullmq"; +import IORedis from "ioredis"; + +import { Channel } from "@ctrlplane/validators/events"; + +import { env } from "./config"; + +const connection = new IORedis(env.REDIS_URL, { maxRetriesPerRequest: null }); + +export const targetScanQueue = new Queue(Channel.TargetScan, { + connection, +}); diff --git a/packages/api/src/redis.ts b/packages/api/src/redis.ts new file mode 100644 index 00000000..96845f67 --- /dev/null +++ b/packages/api/src/redis.ts @@ -0,0 +1,5 @@ +import IORedis from "ioredis"; + +import { env } from "./config"; + +export const redis = new IORedis(env.REDIS_URL, { maxRetriesPerRequest: null }); diff --git a/packages/api/src/router/job.ts b/packages/api/src/router/job.ts index da2a7e5f..f79a30fa 100644 --- a/packages/api/src/router/job.ts +++ b/packages/api/src/router/job.ts @@ -209,11 +209,6 @@ const jobAgentRouter = createTRPCRouter({ .query(async ({ ctx, input }) => ctx.db.select().from(jobAgent).where(eq(jobAgent.workspaceId, input)), ), - byType: publicProcedure - .input(z.string()) - .query(async ({ ctx, input }) => - ctx.db.select().from(jobAgent).where(eq(jobAgent.type, input)), - ), create: protectedProcedure .input(createJobAgent) .mutation(({ ctx, input }) => diff --git a/packages/api/src/router/target.ts b/packages/api/src/router/target.ts index 56988e5f..6101a9d2 100644 --- a/packages/api/src/router/target.ts +++ b/packages/api/src/router/target.ts @@ -1,4 +1,6 @@ import type { SQL, Tx } from "@ctrlplane/db"; +import ms from "ms"; +import { targetScanQueue } from "src/dispatch"; import { isPresent } from "ts-is-present"; import { z } from "zod"; @@ -155,6 +157,13 @@ const targetProviderRouter = createTRPCRouter({ .values({ ...input.config, targetProviderId: tg.id }) .returning() .then(takeFirst); + + await targetScanQueue.add( + tg.id, + { targetProviderId: tg.id }, + { repeat: { every: ms("5m") } }, + ); + return { ...tg, config: tgConfig }; }), ), diff --git a/packages/job-dispatch/package.json b/packages/job-dispatch/package.json index 312c346d..45dfac62 100644 --- a/packages/job-dispatch/package.json +++ b/packages/job-dispatch/package.json @@ -26,7 +26,6 @@ "dependencies": { "@ctrlplane/db": "workspace:*", "@t3-oss/env-core": "^0.10.1", - "amqplib": "^0.10.4", "date-fns": "^3.6.0", "lodash": "^4.17.21", "ms": "^2.1.3", diff --git a/packages/job-dispatch/src/job-dispatch.ts b/packages/job-dispatch/src/job-dispatch.ts index 8d2b0524..a540ab99 100644 --- a/packages/job-dispatch/src/job-dispatch.ts +++ b/packages/job-dispatch/src/job-dispatch.ts @@ -1,95 +1,9 @@ import type { Tx } from "@ctrlplane/db"; -import type { JobConfig, JobExecution } from "@ctrlplane/db/schema"; -import amqp from "amqplib"; +import type { JobConfig } from "@ctrlplane/db/schema"; import _ from "lodash"; -import { isPresent } from "ts-is-present"; - -import { and, eq, inArray, isNull, or } from "@ctrlplane/db"; -import { - deployment, - environment, - jobAgent, - jobConfig, - jobExecution, - release, - runbook, - target, -} from "@ctrlplane/db/schema"; import type { JobExecutionReason } from "./job-execution.js"; -import { env } from "./config.js"; -import { - createJobExecutions, - jobExecutionDataMapper, -} from "./job-execution.js"; - -/** - * @deprecated Moving away from using a queue for dispatching jobExecutions. - */ -const dispatchToAmqp = async (db: Tx, jobExecutions: JobExecution[]) => { - if (jobExecutions.length === 0) return; - - const dispatchData = await db - .select() - .from(jobExecution) - .innerJoin(jobConfig, eq(jobExecution.jobConfigId, jobConfig.id)) - .leftJoin(environment, eq(jobConfig.environmentId, environment.id)) - .leftJoin(target, eq(jobConfig.targetId, target.id)) - .leftJoin(release, eq(jobConfig.releaseId, release.id)) - .leftJoin(runbook, eq(jobConfig.runbookId, runbook.id)) - .leftJoin(deployment, eq(release.deploymentId, deployment.id)) - .innerJoin( - jobAgent, - or( - eq(jobExecution.jobAgentId, jobAgent.id), - eq(runbook.jobAgentId, jobAgent.id), - ), - ) - .where( - and( - inArray( - jobExecution.id, - jobExecutions.map((d) => d.id), - ), - isNull(environment.deletedAt), - ), - ) - .then((ds) => ds.map(jobExecutionDataMapper)); - - if (env.AMQP_URL == null) throw Error("AMQP_URL is not set"); - - const connection = await amqp.connect(env.AMQP_URL); - const channel = await connection.createChannel(); - - await channel.assertQueue(env.AMQP_QUEUE, { durable: true }); - for (const d of dispatchData) { - const data = Buffer.from(JSON.stringify(d)); - channel.sendToQueue(env.AMQP_QUEUE, data, { - persistent: true, - messageId: d.id, - }); - } - - await channel.close(); -}; - -export const dispatchRunbookJobConfigs = async ( - db: Tx, - jobConfigs: JobConfig[], -) => { - const runbooks = jobConfigs.filter((t) => isPresent(t.runbookId)); - const wf = await createJobExecutions(db, runbooks); - - await dispatchToAmqp(db, wf); -}; - -export const dispatchAllJobConfigs = async ( - db: Tx, - jobConfigs: JobConfig[], -) => { - const wf = await createJobExecutions(db, jobConfigs); - await dispatchToAmqp(db, wf); -}; +import { createJobExecutions } from "./job-execution.js"; export type DispatchFilterFunc = ( db: Tx, @@ -136,7 +50,6 @@ class DispatchBuilder { if (t.length === 0) return []; const wfs = await createJobExecutions(this.db, t, undefined, this._reason); - await dispatchToAmqp(this.db, wfs); for (const func of this._then) await func(this.db, t); diff --git a/packages/job-dispatch/src/job-execution.ts b/packages/job-dispatch/src/job-execution.ts index 083fb61b..a3eb1ce2 100644 --- a/packages/job-dispatch/src/job-execution.ts +++ b/packages/job-dispatch/src/job-execution.ts @@ -1,16 +1,6 @@ import type { Tx } from "@ctrlplane/db"; -import type { - Environment, - JobAgent, - JobConfig, - JobExecution, - Release, - Runbook, - Target, - updateJobExecution, -} from "@ctrlplane/db/schema"; +import type { JobConfig, JobExecution } from "@ctrlplane/db/schema"; import _ from "lodash"; -import { z } from "zod"; import { and, eq, inArray, isNull, or, takeFirst } from "@ctrlplane/db"; import { db } from "@ctrlplane/db/client"; @@ -30,59 +20,6 @@ import { dispatchJobConfigs } from "./job-dispatch.js"; import { isPassingAllPolicies } from "./policy-checker.js"; import { cancelOldJobConfigsOnJobDispatch } from "./release-sequencing.js"; -export const jobExecutionData = z.object({ - id: z.string().uuid(), - config: z.record(z.any()), - payload: z - .object({ - jobExecution: z - .object({ - id: z.string().uuid(), - }) - .passthrough(), - jobAgent: z - .object({ - id: z.string().uuid(), - }) - .passthrough(), - }) - .passthrough(), -}); - -export interface JobExecutionData> { - id: string; - jobAgentConfig: T; - payload: { - environment: Environment | null; - target: Target | null; - release: Release | null; - runbook: Runbook | null; - jobExecution: JobExecution; - jobAgent: JobAgent; - }; -} - -export type JobExecutionState = z.infer; - -export const jobExecutionDataMapper = (d: { - job_execution: JobExecution; - target: Target | null; - job_agent: JobAgent; - environment: Environment | null; - release: Release | null; - runbook: Runbook | null; -}): JobExecutionData => ({ - ...d.job_execution, - payload: { - jobAgent: d.job_agent, - environment: d.environment, - target: d.target, - release: d.release, - runbook: d.runbook, - jobExecution: d.job_execution, - }, -}); - type JobExecutionStatusType = | "completed" | "cancelled" @@ -98,8 +35,9 @@ export type JobExecutionReason = | "policy_override" | "env_policy_override" | "config_policy_override"; + /** - * Converts a job config into a jobExecution which means they can now be + * Converts a job config into a job execution which means they can now be * picked up by job agents */ export const createJobExecutions = async ( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fb6495b3..f71db7a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -697,18 +697,27 @@ importers: '@trpc/server': specifier: 11.0.0-rc.364 version: 11.0.0-rc.364 + bullmq: + specifier: ^5.12.10 + version: 5.12.10 google-auth-library: specifier: ^9.13.0 version: 9.13.0 googleapis: specifier: ^140.0.1 version: 140.0.1 + ioredis: + specifier: ^5.4.1 + version: 5.4.1 js-yaml: specifier: ^4.1.0 version: 4.1.0 lodash: specifier: ^4.17.21 version: 4.17.21 + ms: + specifier: ^2.1.3 + version: 2.1.3 superjson: specifier: 2.2.1 version: 2.2.1 @@ -850,9 +859,6 @@ importers: '@t3-oss/env-core': specifier: ^0.10.1 version: 0.10.1(typescript@5.5.3)(zod@3.23.8) - amqplib: - specifier: ^0.10.4 - version: 0.10.4 date-fns: specifier: ^3.6.0 version: 3.6.0