Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions apps/webapp/app/services/agents/provisioning.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { spawn } from "child_process";
import { prisma } from "~/db.server";
import { logger } from "~/services/logger.server";

export class AgentProvisioningService {
private static VPS_IP = "178.128.150.129";
private static SSH_USER = "root";

static async provision(agentId: string) {
const agent = await prisma.agentConfig.findUnique({
where: { id: agentId },
});

if (!agent || !agent.containerName || !agent.containerPort) {
throw new Error("Invalid agent config for provisioning");
}

const { containerName, containerPort } = agent;

logger.info("Starting Docker provisioning on VPS", {
agentId,
containerName,
port: containerPort,
});

// 1. Stop and remove existing container if it exists
await this.runSshCommand(`docker rm -f ${containerName} || true`);

// 2. Run new container
// Note: This assumes the 'openclaw' image is available on the VPS
const dockerRunCmd = `docker run -d --name ${containerName} -p ${containerPort}:8000 --restart always openclaw:latest`;

try {
await this.runSshCommand(dockerRunCmd);

// 3. Update status to healthy if provisioning command succeeded
await prisma.agentConfig.update({
where: { id: agentId },
data: { status: "healthy" },
});

logger.info("Agent provisioning completed successfully", { agentId });
} catch (error) {
logger.error("Docker run failed", { agentId, error });

await prisma.agentConfig.update({
where: { id: agentId },
data: { status: "unhealthy" },
});

await prisma.agentHealthCheck.create({
data: {
agentId,
isHealthy: false,
errorMessage: error instanceof Error ? error.message : "Docker run failed",
},
});

throw error;
}
}

private static runSshCommand(command: string): Promise<string> {
return new Promise((resolve, reject) => {
// Assumes SSH key is configured for the root user on the host running the webapp
const ssh = spawn("ssh", [
"-o", "StrictHostKeyChecking=no",
`${this.SSH_USER}@${this.VPS_IP}`,
command
]);

let stdout = "";
let stderr = "";

ssh.stdout.on("data", (data: Buffer) => {
stdout += data.toString();
});

ssh.stderr.on("data", (data: Buffer) => {
stderr += data.toString();
});

ssh.on("close", (code: number | null) => {
if (code === 0) {
resolve(stdout.trim());
} else {
reject(new Error(`SSH command failed with code ${code}: ${stderr.trim()}`));
}
});

ssh.on("error", (err: Error) => {
reject(err);
});
});
}
}
6 changes: 1 addition & 5 deletions apps/webapp/app/services/worker.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
} from "~/v3/services/cancelDevSessionRuns.server";
import { CancelTaskAttemptDependenciesService } from "~/v3/services/cancelTaskAttemptDependencies.server";
import { EnqueueDelayedRunService } from "~/v3/services/enqueueDelayedRun.server";
import { ExecuteTasksWaitingForDeployService } from "~/v3/services/executeTasksWaitingForDeploy";
import { ExpireEnqueuedRunService } from "~/v3/services/expireEnqueuedRun.server";
import { ResumeBatchRunService } from "~/v3/services/resumeBatchRun.server";
import { ResumeTaskDependencyService } from "~/v3/services/resumeTaskDependency.server";
Expand Down Expand Up @@ -199,9 +198,6 @@ function getWorkerQueue() {
priority: 0,
maxAttempts: 5,
handler: async (payload, job) => {
const service = new ExecuteTasksWaitingForDeployService();

return await service.call(payload.backgroundWorkerId);
},
},
// @deprecated, moved to ScheduleEngine
Expand Down Expand Up @@ -267,7 +263,7 @@ function getWorkerQueue() {
"v3.requeueTaskRun": {
priority: 0,
maxAttempts: 3,
handler: async (payload, job) => {}, // This is now handled by redisWorker
handler: async (payload, job) => { }, // This is now handled by redisWorker
},
// @deprecated, moved to commonWorker.server.ts
"v3.retryAttempt": {
Expand Down
3 changes: 0 additions & 3 deletions apps/webapp/app/v3/commonWorker.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { BatchTriggerV3Service } from "./services/batchTriggerV3.server";
import { CancelDevSessionRunsService } from "./services/cancelDevSessionRuns.server";
import { CancelTaskAttemptDependenciesService } from "./services/cancelTaskAttemptDependencies.server";
import { EnqueueDelayedRunService } from "./services/enqueueDelayedRun.server";
import { ExecuteTasksWaitingForDeployService } from "./services/executeTasksWaitingForDeploy";
import { ExpireEnqueuedRunService } from "./services/expireEnqueuedRun.server";
import { ResumeBatchRunService } from "./services/resumeBatchRun.server";
import { ResumeTaskDependencyService } from "./services/resumeTaskDependency.server";
Expand Down Expand Up @@ -226,8 +225,6 @@ function initializeWorker() {
await service.call(payload.deploymentId, payload.fromStatus, payload.errorMessage);
},
"v3.executeTasksWaitingForDeploy": async ({ payload }) => {
const service = new ExecuteTasksWaitingForDeployService();
await service.call(payload.backgroundWorkerId);
},
"v3.retryAttempt": async ({ payload }) => {
const service = new RetryAttemptService();
Expand Down
64 changes: 64 additions & 0 deletions apps/webapp/app/v3/services/agents/healthCheck.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { prisma } from "~/db.server";
import { logger } from "~/services/logger.server";

export class AgentHealthCheckService {
private static VPS_IP = "178.128.150.129";

public async call() {
const agents = await prisma.agentConfig.findMany({
where: {
status: { in: ["healthy", "provisioning", "unhealthy"] },
containerPort: { not: null },
},
});

logger.debug(`Running health checks for ${agents.length} agents`);

for (const agent of agents) {
await this.checkAgent(agent);
}
}

private async checkAgent(agent: any) {
const url = `http://${AgentHealthCheckService.VPS_IP}:${agent.containerPort}/api/health`;
const start = Date.now();

try {
const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
const duration = Date.now() - start;

if (response.ok) {
await this.updateStatus(agent.id, true, duration);
} else {
await this.updateStatus(agent.id, false, duration, `Health check returned ${response.status}`);
}
} catch (error) {
const duration = Date.now() - start;
const errorMessage = error instanceof Error ? error.message : "Unknown error";

await this.updateStatus(agent.id, false, duration, errorMessage);
}
}

private async updateStatus(agentId: string, isHealthy: boolean, duration: number, error?: string) {
const status = isHealthy ? "healthy" : "unhealthy";

await prisma.agentConfig.update({
where: { id: agentId },
data: { status },
});

await prisma.agentHealthCheck.create({
data: {
agentId,
isHealthy,
responseTimeMs: duration,
errorMessage: error,
},
});

if (!isHealthy) {
logger.warn(`Agent ${agentId} is unhealthy`, { error, duration });
}
}
}
3 changes: 0 additions & 3 deletions apps/webapp/app/v3/services/changeCurrentDeployment.server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { WorkerDeployment } from "@trigger.dev/database";
import { BaseService, ServiceValidationError } from "./baseService.server";
import { ExecuteTasksWaitingForDeployService } from "./executeTasksWaitingForDeploy";
import { compareDeploymentVersions } from "../utils/deploymentVersions";
import { CURRENT_DEPLOYMENT_LABEL } from "@trigger.dev/core/v3/isomorphic";

Expand Down Expand Up @@ -95,7 +94,5 @@ export class ChangeCurrentDeploymentService extends BaseService {
deploymentId: deployment.id,
},
});

await ExecuteTasksWaitingForDeployService.enqueue(deployment.workerId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { updateEnvConcurrencyLimits } from "../runQueue.server";
import { PerformDeploymentAlertsService } from "./alerts/performDeploymentAlerts.server";
import { BaseService } from "./baseService.server";
import { createWorkerResources, syncDeclarativeSchedules } from "./createBackgroundWorker.server";
import { ExecuteTasksWaitingForDeployService } from "./executeTasksWaitingForDeploy";
import { projectPubSub } from "./projectPubSub.server";
import { TimeoutDeploymentService } from "./timeoutDeployment.server";
import { CURRENT_DEPLOYMENT_LABEL, BackgroundWorkerId } from "@trigger.dev/core/v3/isomorphic";
Expand Down Expand Up @@ -162,7 +161,6 @@ export class CreateDeploymentBackgroundWorkerServiceV3 extends BaseService {
});
}

await ExecuteTasksWaitingForDeployService.enqueue(backgroundWorker.id);
await PerformDeploymentAlertsService.enqueue(deployment.id);
await TimeoutDeploymentService.dequeue(deployment.id, this._prisma);

Expand Down
117 changes: 0 additions & 117 deletions apps/webapp/app/v3/services/executeTasksWaitingForDeploy.ts

This file was deleted.

Binary file added pr_list.json
Binary file not shown.
6 changes: 3 additions & 3 deletions references/d3-chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@
"@trigger.dev/build": "workspace:*",
"@types/marked": "^4.0.3",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@types/react": "18.2.69",
"@types/react-dom": "18.2.7",
"tailwindcss": "^4.0.17",
"trigger.dev": "workspace:*",
"typescript": "^5"
}
}
}
6 changes: 3 additions & 3 deletions references/d3-openai-agents/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@
"@tailwindcss/postcss": "^4",
"@trigger.dev/build": "workspace:*",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@types/react": "18.2.69",
"@types/react-dom": "18.2.7",
"dotenv": "16.4.7",
"tailwindcss": "^4.0.17",
"trigger.dev": "workspace:*",
"tsx": "4.19.3",
"typescript": "^5"
}
}
}
4 changes: 2 additions & 2 deletions references/realtime-hooks-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@types/react": "18.2.69",
"@types/react-dom": "18.2.7",
"tailwindcss": "^4",
"trigger.dev": "workspace:*",
"typescript": "^5"
Expand Down
Loading