Move the ingestion of compute to the platform

This commit is contained in:
Matt Aitken
2024-07-03 17:46:11 +01:00
parent 97537e677d
commit 18f883d7de
3 changed files with 15 additions and 135 deletions
+6 -88
View File
@@ -1,24 +1,6 @@
import { ActionFunctionArgs } from "@remix-run/server-runtime";
import { MachinePresetName } from "@trigger.dev/core/v3";
import { z } from "zod";
import { prisma } from "~/db.server";
import { validateJWTTokenAndRenew } from "~/services/apiAuth.server";
import { logger } from "~/services/logger.server";
import { workerQueue } from "~/services/worker.server";
import { machinePresetFromName } from "~/v3/machinePresets.server";
import { reportUsageEvent } from "~/v3/openMeter.server";
const JWTPayloadSchema = z.object({
environment_id: z.string(),
org_id: z.string(),
project_id: z.string(),
run_id: z.string(),
machine_preset: z.string(),
});
const BodySchema = z.object({
durationMs: z.number(),
});
import { reportComputeUsage } from "~/services/platform.v3.server";
export async function action({ request }: ActionFunctionArgs) {
// Ensure this is a POST request
@@ -26,74 +8,10 @@ export async function action({ request }: ActionFunctionArgs) {
return { status: 405, body: "Method Not Allowed" };
}
const jwtResult = await validateJWTTokenAndRenew(request, JWTPayloadSchema);
if (!jwtResult) {
return { status: 401, body: "Unauthorized" };
try {
return await reportComputeUsage(request);
} catch (e) {
logger.error("Error reporting compute usage", { error: e });
return new Response(null, { status: 500 });
}
const rawJson = await request.json();
const json = BodySchema.safeParse(rawJson);
if (!json.success) {
logger.error("Failed to parse request body", { rawJson });
return { status: 400, body: "Bad Request" };
}
const preset = machinePresetFromName(jwtResult.payload.machine_preset as MachinePresetName);
logger.debug("[/api/v1/usage/ingest] Reporting usage", { jwtResult, json: json.data, preset });
if (json.data.durationMs > 0) {
const costInCents = json.data.durationMs * preset.centsPerMs;
const taskRun = await prisma.taskRun.update({
where: {
id: jwtResult.payload.run_id,
},
data: {
usageDurationMs: {
increment: json.data.durationMs,
},
costInCents: {
increment: json.data.durationMs * preset.centsPerMs,
},
},
});
try {
await reportUsageEvent({
source: "webapp",
type: "usage",
subject: jwtResult.payload.org_id,
data: {
durationMs: json.data.durationMs,
costInCents: String(costInCents),
taskIdentifier: taskRun.taskIdentifier,
},
});
} catch (e) {
logger.error("Failed to report usage event, enqueing v3.reportUsage", { error: e });
await workerQueue.enqueue("v3.reportUsage", {
orgId: jwtResult.payload.org_id,
data: {
costInCents: String(costInCents),
},
additionalData: {
durationMs: json.data.durationMs,
taskIdentifier: taskRun.taskIdentifier,
},
});
}
}
return new Response(null, {
status: 200,
headers: {
"x-trigger-jwt": jwtResult.jwt,
},
});
}
@@ -181,6 +181,15 @@ export async function getUsageSeries(organizationId: string, params: UsageSeries
}
}
export async function reportComputeUsage(request: Request) {
const client = getClient();
if (!client) return undefined;
return fetch(`${process.env.BILLING_API_URL}/api/v1/usage/ingest/compute`, {
method: "POST",
headers: request.headers,
body: await request.text(),
});
}
export async function projectCreated(organization: Organization, project: Project) {
if (project.version === "V2" || !isCloud()) {
await createEnvironment(organization, project, "STAGING");
-47
View File
@@ -1,47 +0,0 @@
import { randomUUID } from "node:crypto";
import { env } from "~/env.server";
import { logger } from "~/services/logger.server";
export type UsageEvent = {
source: string;
subject: string;
type: string;
id?: string;
time?: Date;
data?: Record<string, unknown>;
};
export async function reportUsageEvent(event: UsageEvent) {
if (!env.USAGE_OPEN_METER_BASE_URL || !env.USAGE_OPEN_METER_API_KEY) {
return;
}
const body = {
specversion: "1.0",
id: event.id ?? randomUUID(),
source: event.source,
type: event.type,
time: (event.time ?? new Date()).toISOString(),
subject: event.subject,
datacontenttype: "application/json",
data: event.data,
};
const url = `${env.USAGE_OPEN_METER_BASE_URL}/api/v1/events`;
logger.debug("Reporting usage event to OpenMeter", { url, body });
const response = await fetch(url, {
method: "POST",
body: JSON.stringify(body),
headers: {
"Content-Type": "application/cloudevents+json",
Authorization: `Bearer ${env.USAGE_OPEN_METER_API_KEY}`,
Accept: "application/json",
},
});
if (!response.ok) {
logger.error(`Failed to report usage event: ${response.status} ${response.statusText}`);
}
}