Canvas: Add worker kill action to monitoring tab

Change-Id: I8387dcf2320f9eccdb2e443fd4039e91ff35ed31
diff --git a/apps/canvas/back/src/project_monitor.ts b/apps/canvas/back/src/project_monitor.ts
index df20e05..7dd2f3c 100644
--- a/apps/canvas/back/src/project_monitor.ts
+++ b/apps/canvas/back/src/project_monitor.ts
@@ -109,6 +109,23 @@
 			throw error; // Re-throw to be caught by ProjectMonitor
 		}
 	}
+
+	async terminateWorker(workerId: string): Promise<void> {
+		const workerAddress = this.workers.get(workerId);
+		if (!workerAddress) {
+			throw new Error(`Worker ${workerId} not found in service ${this.serviceName}`);
+		}
+		try {
+			const response = await fetch(`${workerAddress}/quitquitquit`, { method: "POST" });
+			if (!response.ok) {
+				throw new Error(`Failed to terminate worker ${workerId} at ${workerAddress}: ${response.statusText}`);
+			}
+			console.log(`Terminated worker ${workerId} in service ${this.serviceName}`);
+		} catch (error) {
+			console.error(`Error terminating worker ${workerId} in service ${this.serviceName}:`, error);
+			throw error; // Re-throw to be caught by ProjectMonitor
+		}
+	}
 }
 
 export class ProjectMonitor {
@@ -173,4 +190,12 @@
 		}
 		await serviceMonitor.reloadWorker(workerId);
 	}
+
+	async terminateWorker(serviceName: string, workerId: string): Promise<void> {
+		const serviceMonitor = this.serviceMonitors.get(serviceName);
+		if (!serviceMonitor) {
+			throw new Error(`Service ${serviceName} not found`);
+		}
+		await serviceMonitor.terminateWorker(workerId);
+	}
 }