diff --git a/packages/shared/src/types/environment.ts b/packages/shared/src/types/environment.ts index 9e38f2d5585..48c6e971715 100644 --- a/packages/shared/src/types/environment.ts +++ b/packages/shared/src/types/environment.ts @@ -71,7 +71,7 @@ export interface Environment { updatedAt: Date; } -export type EnvironmentDeleteBlockedReason = "managed_local" | "instance_default"; +export type EnvironmentDeleteBlockedReason = "managed_local" | "instance_default" | "active_runtime_use"; export interface EnvironmentDeleteBlastRadius { environmentId: string; diff --git a/server/src/services/environments.ts b/server/src/services/environments.ts index 6487f7a1b9e..4342a12a82d 100644 --- a/server/src/services/environments.ts +++ b/server/src/services/environments.ts @@ -552,11 +552,13 @@ export function environmentService(db: Db) { const isManagedLocal = environment.driver === "local"; const isInstanceDefault = countFromRows(instanceDefaultRows) > 0; + const activeLeaseCount = countFromRows(activeLeaseRows); + const activeCustomImageSetupSessionCount = countFromRows(activeSetupRows); + const hasActiveRuntimeUse = activeLeaseCount > 0 || activeCustomImageSetupSessionCount > 0; const deleteBlockedReasons: EnvironmentDeleteBlockedReason[] = []; if (isManagedLocal) deleteBlockedReasons.push("managed_local"); if (isInstanceDefault) deleteBlockedReasons.push("instance_default"); - const activeLeaseCount = countFromRows(activeLeaseRows); - const activeCustomImageSetupSessionCount = countFromRows(activeSetupRows); + if (hasActiveRuntimeUse) deleteBlockedReasons.push("active_runtime_use"); return { environmentId: id, @@ -574,11 +576,21 @@ export function environmentService(db: Db) { activeRuntimeUse: { activeLeaseCount, activeCustomImageSetupSessionCount, - hasActiveRuntimeUse: activeLeaseCount > 0 || activeCustomImageSetupSessionCount > 0, + hasActiveRuntimeUse, }, }; }, + releaseActiveLeasesForEnvironment: async (id: string): Promise => { + const now = new Date(); + const rows = await db + .update(environmentLeases) + .set({ status: "released", releasedAt: now, lastUsedAt: now, updatedAt: now }) + .where(and(eq(environmentLeases.environmentId, id), eq(environmentLeases.status, "active"))) + .returning(); + return rows.length; + }, + listLeases: async ( environmentId: string, filters: {