From 43549773e9d6216e1556709cb4977a92ec03e7cb Mon Sep 17 00:00:00 2001 From: nicktrn <55853254+nicktrn@users.noreply.github.com> Date: Tue, 14 Oct 2025 12:40:11 +0100 Subject: [PATCH 1/3] chore(billing): improve logs to distinguish between failure modes --- .../webapp/app/services/platform.v3.server.ts | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/webapp/app/services/platform.v3.server.ts b/apps/webapp/app/services/platform.v3.server.ts index f964470625..c58ed1218e 100644 --- a/apps/webapp/app/services/platform.v3.server.ts +++ b/apps/webapp/app/services/platform.v3.server.ts @@ -205,7 +205,7 @@ export async function getCurrentPlan(orgId: string) { firstDayOfNextMonth.setUTCHours(0, 0, 0, 0); if (!result.success) { - logger.error("Error getting current plan", { orgId, error: result.error }); + logger.error("Error getting current plan - no success", { orgId, error: result.error }); return undefined; } @@ -221,7 +221,7 @@ export async function getCurrentPlan(orgId: string) { return { ...result, usage }; } catch (e) { - logger.error("Error getting current plan", { orgId, error: e }); + logger.error("Error getting current plan - caught error", { orgId, error: e }); return undefined; } } @@ -232,13 +232,13 @@ export async function getLimits(orgId: string) { try { const result = await client.currentPlan(orgId); if (!result.success) { - logger.error("Error getting limits", { orgId, error: result.error }); + logger.error("Error getting limits - no success", { orgId, error: result.error }); return undefined; } return result.v3Subscription?.plan?.limits; } catch (e) { - logger.error("Error getting limits", { orgId, error: e }); + logger.error("Error getting limits - caught error", { orgId, error: e }); return undefined; } } @@ -279,12 +279,12 @@ export async function getPlans() { try { const result = await client.plans(); if (!result.success) { - logger.error("Error getting plans", { error: result.error }); + logger.error("Error getting plans - no success", { error: result.error }); return undefined; } return result; } catch (e) { - logger.error("Error getting plans", { error: e }); + logger.error("Error getting plans - caught error", { error: e }); return undefined; } } @@ -362,12 +362,12 @@ export async function getUsage(organizationId: string, { from, to }: { from: Dat try { const result = await client.usage(organizationId, { from, to }); if (!result.success) { - logger.error("Error getting usage", { error: result.error }); + logger.error("Error getting usage - no success", { error: result.error }); return undefined; } return result; } catch (e) { - logger.error("Error getting usage", { error: e }); + logger.error("Error getting usage - caught error", { error: e }); return undefined; } } @@ -396,12 +396,12 @@ export async function getUsageSeries(organizationId: string, params: UsageSeries try { const result = await client.usageSeries(organizationId, params); if (!result.success) { - logger.error("Error getting usage series", { error: result.error }); + logger.error("Error getting usage series - no success", { error: result.error }); return undefined; } return result; } catch (e) { - logger.error("Error getting usage series", { error: e }); + logger.error("Error getting usage series - caught error", { error: e }); return undefined; } } @@ -420,12 +420,12 @@ export async function reportInvocationUsage( additionalData, }); if (!result.success) { - logger.error("Error reporting invocation", { error: result.error }); + logger.error("Error reporting invocation - no success", { error: result.error }); return undefined; } return result; } catch (e) { - logger.error("Error reporting invocation", { error: e }); + logger.error("Error reporting invocation - caught error", { error: e }); return undefined; } } @@ -448,14 +448,14 @@ export async function getEntitlement( try { const result = await client.getEntitlement(organizationId); if (!result.success) { - logger.error("Error getting entitlement", { error: result.error }); + logger.error("Error getting entitlement - no success", { error: result.error }); return { hasAccess: true as const, }; } return result; } catch (e) { - logger.error("Error getting entitlement", { error: e }); + logger.error("Error getting entitlement - caught error", { error: e }); return { hasAccess: true as const, }; From 57a3438d1047ba2ecf29350900ba87370a061cb8 Mon Sep 17 00:00:00 2001 From: nicktrn <55853254+nicktrn@users.noreply.github.com> Date: Tue, 14 Oct 2025 12:41:17 +0100 Subject: [PATCH 2/3] fix(engine): default to paid placement on billing errors --- apps/webapp/app/v3/runEngine.server.ts | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/webapp/app/v3/runEngine.server.ts b/apps/webapp/app/v3/runEngine.server.ts index da01bd44db..d21ef2425c 100644 --- a/apps/webapp/app/v3/runEngine.server.ts +++ b/apps/webapp/app/v3/runEngine.server.ts @@ -5,6 +5,7 @@ import { defaultMachine, getCurrentPlan } from "~/services/platform.v3.server"; import { singleton } from "~/utils/singleton"; import { allMachines } from "./machinePresets.server"; import { meter, tracer } from "./tracer.server"; +import { logger } from "~/services/logger.server"; export const engine = singleton("RunEngine", createRunEngine); @@ -120,23 +121,37 @@ function createRunEngine() { getCurrentPlan: async (orgId: string) => { const plan = await getCurrentPlan(orgId); + // This only happens when there's no billing service running or on errors if (!plan) { + logger.warn("engine.getCurrentPlan: no plan", { orgId }); return { - isPaying: false, - type: "free", + isPaying: true, + type: "paid", // default to paid }; } + // This shouldn't happen if (!plan.v3Subscription) { + logger.warn("engine.getCurrentPlan: no v3 subscription", { orgId }); return { isPaying: false, type: "free", }; } + // Neither should this + if (!plan.v3Subscription.plan) { + logger.warn("engine.getCurrentPlan: no v3 subscription plan", { orgId }); + return { + isPaying: plan.v3Subscription.isPaying, + type: "free", + }; + } + + // This is the normal case when the billing service is running return { isPaying: plan.v3Subscription.isPaying, - type: plan.v3Subscription.plan?.type ?? "free", + type: plan.v3Subscription.plan.type, }; }, }, From d92731f3815791c890b9058269566c2838b7109b Mon Sep 17 00:00:00 2001 From: nicktrn <55853254+nicktrn@users.noreply.github.com> Date: Tue, 14 Oct 2025 13:15:58 +0100 Subject: [PATCH 3/3] chore(engine): set plan type according to paying field when missing --- apps/webapp/app/v3/runEngine.server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/webapp/app/v3/runEngine.server.ts b/apps/webapp/app/v3/runEngine.server.ts index d21ef2425c..4fb7083e6b 100644 --- a/apps/webapp/app/v3/runEngine.server.ts +++ b/apps/webapp/app/v3/runEngine.server.ts @@ -144,7 +144,7 @@ function createRunEngine() { logger.warn("engine.getCurrentPlan: no v3 subscription plan", { orgId }); return { isPaying: plan.v3Subscription.isPaying, - type: "free", + type: plan.v3Subscription.isPaying ? "paid" : "free", }; }