import { EnvironmentPauseSource, type Organization, type Project, type RuntimeEnvironment, type RuntimeEnvironmentType, } from "@trigger.dev/database"; import type { BillingLimitResult } from "~/services/billingLimit.schemas"; import { logger } from "~/services/logger.server"; import { isBillableEnvironmentType } from "./billingLimitConstants"; import { resolveConvergeTargetFromBillingLimit } from "./billingLimitReconciliation.server"; export type InitialEnvPauseState = { paused: boolean; pauseSource: typeof EnvironmentPauseSource.BILLING_LIMIT | null; }; export type GetInitialEnvPauseStateDeps = { getBillingLimit?: (organizationId: string) => Promise; }; export async function getInitialEnvPauseStateForBillingLimit( organizationId: string, type: RuntimeEnvironmentType, deps: GetInitialEnvPauseStateDeps = {} ): Promise { if (!isBillableEnvironmentType(type)) { return { paused: false, pauseSource: null }; } let billingLimit: BillingLimitResult | undefined; try { billingLimit = deps.getBillingLimit ? await deps.getBillingLimit(organizationId) : await (await import("~/services/platform.v3.server")).getBillingLimit(organizationId); } catch (error) { logger.error("Failed to fetch billing limit for initial env pause state", { organizationId, error, }); return { paused: false, pauseSource: null }; } const targetState = resolveConvergeTargetFromBillingLimit(billingLimit); if (targetState === "grace" || targetState === "rejected") { return { paused: true, pauseSource: EnvironmentPauseSource.BILLING_LIMIT, }; } return { paused: false, pauseSource: null }; } export async function applyBillingLimitPauseAfterEnvCreate( environment: RuntimeEnvironment & { organization: Organization; project: Project } ): Promise { if (!environment.paused || environment.pauseSource !== EnvironmentPauseSource.BILLING_LIMIT) { return; } try { // Imported dynamically so this module (pulled in at module load by // upsertBranch.server.ts) doesn't eagerly load runQueue.server -> marqs -> // triggerTaskV1 -> the autoIncrementCounter singleton, which throws when // REDIS_HOST/REDIS_PORT are unset (e.g. the webapp unit-test CI job). const { updateEnvConcurrencyLimits } = await import("~/v3/runQueue.server"); await updateEnvConcurrencyLimits(environment, 0); } catch (error) { logger.error("Failed to apply billing-limit pause after env create", { environmentId: environment.id, organizationId: environment.organizationId, error, }); } }