chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
import type { FinalizeDeploymentRequestBody } from "@trigger.dev/core/v3/schemas";
|
||||
import type { AuthenticatedEnvironment } from "~/services/apiAuth.server";
|
||||
import { logger } from "~/services/logger.server";
|
||||
import { socketIo } from "../handleSocketIo.server";
|
||||
import { updateEnvConcurrencyLimits } from "../runQueue.server";
|
||||
import { PerformDeploymentAlertsService } from "./alerts/performDeploymentAlerts.server";
|
||||
import { BaseService, ServiceValidationError } from "./baseService.server";
|
||||
import { ChangeCurrentDeploymentService } from "./changeCurrentDeployment.server";
|
||||
import { projectPubSub } from "./projectPubSub.server";
|
||||
import { FailDeploymentService } from "./failDeployment.server";
|
||||
import { TimeoutDeploymentService } from "./timeoutDeployment.server";
|
||||
import { DeploymentService } from "./deployment.server";
|
||||
import { recordDeploymentOutcome } from "./recordDeploymentOutcome.server";
|
||||
import { engine } from "../runEngine.server";
|
||||
import { tryCatch } from "@trigger.dev/core";
|
||||
|
||||
export class FinalizeDeploymentService extends BaseService {
|
||||
public async call(
|
||||
authenticatedEnv: AuthenticatedEnvironment,
|
||||
id: string,
|
||||
body: FinalizeDeploymentRequestBody
|
||||
) {
|
||||
const deployment = await this._prisma.workerDeployment.findFirst({
|
||||
where: {
|
||||
friendlyId: id,
|
||||
environmentId: authenticatedEnv.id,
|
||||
},
|
||||
include: {
|
||||
worker: {
|
||||
include: {
|
||||
tasks: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!deployment) {
|
||||
logger.error("Worker deployment not found", { id });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!deployment.worker) {
|
||||
logger.error("Worker deployment does not have a worker", { id });
|
||||
|
||||
const failService = new FailDeploymentService();
|
||||
await failService.call(authenticatedEnv, deployment.friendlyId, {
|
||||
error: {
|
||||
name: "MissingWorker",
|
||||
message: "Deployment does not have a worker",
|
||||
},
|
||||
});
|
||||
|
||||
throw new ServiceValidationError("Worker deployment does not have a worker");
|
||||
}
|
||||
|
||||
if (deployment.status === "DEPLOYED") {
|
||||
logger.debug("Worker deployment is already deployed", { id });
|
||||
|
||||
return deployment;
|
||||
}
|
||||
|
||||
if (deployment.status !== "DEPLOYING") {
|
||||
logger.error("Worker deployment is not in DEPLOYING status", { id });
|
||||
throw new ServiceValidationError("Worker deployment is not in DEPLOYING status");
|
||||
}
|
||||
|
||||
const imageDigest = validatedImageDigest(body.imageDigest);
|
||||
|
||||
// Link the deployment with the background worker
|
||||
const finalizedDeployment = await this._prisma.workerDeployment.update({
|
||||
where: {
|
||||
id: deployment.id,
|
||||
},
|
||||
data: {
|
||||
status: "DEPLOYED",
|
||||
deployedAt: new Date(),
|
||||
// Only add the digest, if any
|
||||
imageReference: imageDigest ? `${deployment.imageReference}@${imageDigest}` : undefined,
|
||||
},
|
||||
});
|
||||
|
||||
recordDeploymentOutcome({
|
||||
status: "DEPLOYED",
|
||||
deploymentFriendlyId: deployment.friendlyId,
|
||||
organizationId: authenticatedEnv.organizationId,
|
||||
projectId: authenticatedEnv.projectId,
|
||||
environmentId: authenticatedEnv.id,
|
||||
environmentType: authenticatedEnv.type,
|
||||
});
|
||||
|
||||
const deploymentService = new DeploymentService();
|
||||
await deploymentService
|
||||
.appendToEventLog(authenticatedEnv.project, finalizedDeployment, [
|
||||
{
|
||||
type: "finalized",
|
||||
data: {
|
||||
result: "succeeded",
|
||||
},
|
||||
},
|
||||
])
|
||||
.orTee((error) => {
|
||||
logger.error("Failed to append finalized deployment event to event log", { error });
|
||||
});
|
||||
|
||||
await TimeoutDeploymentService.dequeue(deployment.id, this._prisma);
|
||||
|
||||
if (typeof body.skipPromotion === "undefined" || !body.skipPromotion) {
|
||||
const promotionService = new ChangeCurrentDeploymentService();
|
||||
|
||||
await promotionService.call(finalizedDeployment, "promote");
|
||||
}
|
||||
|
||||
try {
|
||||
//send a notification that a new worker has been created
|
||||
await projectPubSub.publish(
|
||||
`project:${authenticatedEnv.projectId}:env:${authenticatedEnv.id}`,
|
||||
"WORKER_CREATED",
|
||||
{
|
||||
environmentId: authenticatedEnv.id,
|
||||
environmentType: authenticatedEnv.type,
|
||||
createdAt: authenticatedEnv.createdAt,
|
||||
taskCount: deployment.worker.tasks.length,
|
||||
type: "deployed",
|
||||
}
|
||||
);
|
||||
|
||||
await updateEnvConcurrencyLimits(authenticatedEnv);
|
||||
} catch (err) {
|
||||
logger.error("Failed to publish WORKER_CREATED event", { err });
|
||||
}
|
||||
|
||||
if (finalizedDeployment.imageReference) {
|
||||
socketIo.providerNamespace.emit("PRE_PULL_DEPLOYMENT", {
|
||||
version: "v1",
|
||||
imageRef: finalizedDeployment.imageReference,
|
||||
shortCode: finalizedDeployment.shortCode,
|
||||
// identifiers
|
||||
deploymentId: finalizedDeployment.id,
|
||||
envId: authenticatedEnv.id,
|
||||
envType: authenticatedEnv.type,
|
||||
orgId: authenticatedEnv.organizationId,
|
||||
projectId: finalizedDeployment.projectId,
|
||||
});
|
||||
}
|
||||
|
||||
if (deployment.worker.engine === "V2") {
|
||||
const [schedulePendingVersionsError] = await tryCatch(
|
||||
engine.scheduleEnqueueRunsForBackgroundWorker(deployment.worker.id)
|
||||
);
|
||||
|
||||
if (schedulePendingVersionsError) {
|
||||
logger.error("Error scheduling pending versions", {
|
||||
error: schedulePendingVersionsError,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await PerformDeploymentAlertsService.enqueue(deployment.id);
|
||||
|
||||
return finalizedDeployment;
|
||||
}
|
||||
}
|
||||
|
||||
function validatedImageDigest(imageDigest?: string): string | undefined {
|
||||
if (!imageDigest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!/^sha256:[a-f0-9]{64}$/.test(imageDigest.trim())) {
|
||||
logger.error("Invalid image digest", { imageDigest });
|
||||
return;
|
||||
}
|
||||
|
||||
return imageDigest.trim();
|
||||
}
|
||||
Reference in New Issue
Block a user