Canvas: Implement worker to manager communication
Register workers on manager side.
Let user force reload service workers.
Change-Id: I2635a04167e7c853151d8a1f5c3511646181a063
diff --git a/apps/canvas/back/src/index.ts b/apps/canvas/back/src/index.ts
index 65eab15..0a35dfe 100644
--- a/apps/canvas/back/src/index.ts
+++ b/apps/canvas/back/src/index.ts
@@ -3,9 +3,13 @@
import { env } from "node:process";
import axios from "axios";
import { GithubClient } from "./github";
+import { z } from "zod";
const db = new PrismaClient();
+// Map to store worker addresses by project ID
+const workers = new Map<number, string[]>();
+
const handleProjectCreate: express.Handler = async (req, resp) => {
try {
const { id } = await db.project.create({
@@ -346,6 +350,8 @@
resp.status(200);
resp.write(
JSON.stringify({
+ // TODO(gio): get from env or command line flags
+ managerAddr: "http://10.42.0.239:8080",
deployKey: project.deployKey,
integrations: {
github: !!project.githubToken,
@@ -371,6 +377,88 @@
}
};
+const WorkerSchema = z.object({
+ address: z.string().url(),
+});
+
+const handleRegisterWorker: express.Handler = async (req, resp) => {
+ try {
+ const projectId = Number(req.params["projectId"]);
+
+ const result = WorkerSchema.safeParse(req.body);
+ console.log(result);
+ if (!result.success) {
+ resp.status(400);
+ resp.write(
+ JSON.stringify({
+ error: "Invalid request data",
+ details: result.error.format(),
+ }),
+ );
+ return;
+ }
+
+ const { address } = result.data;
+
+ // Get existing workers or initialize empty array
+ const projectWorkers = workers.get(projectId) || [];
+
+ // Add new worker if not already present
+ if (!projectWorkers.includes(address)) {
+ projectWorkers.push(address);
+ }
+
+ workers.set(projectId, projectWorkers);
+
+ resp.status(200);
+ resp.write(
+ JSON.stringify({
+ success: true,
+ workers: projectWorkers,
+ }),
+ );
+ } catch (e) {
+ console.log(e);
+ resp.status(500);
+ resp.write(JSON.stringify({ error: "Failed to register worker" }));
+ } finally {
+ resp.end();
+ }
+};
+
+const handleReload: express.Handler = async (req, resp) => {
+ try {
+ const projectId = Number(req.params["projectId"]);
+ const projectWorkers = workers.get(projectId) || [];
+
+ if (projectWorkers.length === 0) {
+ resp.status(404);
+ resp.write(JSON.stringify({ error: "No workers registered for this project" }));
+ return;
+ }
+
+ await Promise.all(
+ projectWorkers.map(async (workerAddress) => {
+ try {
+ const updateEndpoint = `${workerAddress}/update`;
+ await axios.post(updateEndpoint);
+ } catch (error: any) {
+ console.log(`Failed to update worker ${workerAddress}: ${error.message || "Unknown error"}`);
+ }
+ }),
+ );
+
+ resp.status(200);
+ resp.write(JSON.stringify({ success: true }));
+ } catch (e) {
+ console.log(e);
+ resp.status(500);
+ resp.write(JSON.stringify({ error: "Failed to reload workers" }));
+ } finally {
+ resp.end();
+ }
+};
+
async function start() {
await db.$connect();
const app = express();
@@ -385,6 +473,8 @@
app.get("/api/project/:projectId/repos/github", handleGithubRepos);
app.post("/api/project/:projectId/github-token", handleUpdateGithubToken);
app.get("/api/project/:projectId/env", handleEnv);
+ app.post("/api/project/:projectId/workers", handleRegisterWorker);
+ app.post("/api/project/:projectId/reload", handleReload);
app.use("/", express.static("../front/dist"));
app.listen(env.DODO_PORT_WEB, () => {
console.log("started");