Jelajahi Sumber

fix(api): reconcile scheduler registration on workflow update

updateWorkflow registered a workflow with the scheduler when its active flag
was true, but had no matching branch for false. Saving a workflow with
active false persisted the flag while leaving the scheduler registration in
place, so a workflow that looked deactivated kept firing on its interval.
Only POST /deactivate actually stopped it.

The update path now reconciles in both directions, so the stored flag and the
scheduler cannot drift apart regardless of which mechanism a client uses.
Both remain supported: silently ignoring an active field the client set would
misreport what happened.

Flipping the flag through an update now also emits workflows.activated or
workflows.deactivated, matching the dedicated endpoints, so listeners see the
state change however it was made.
fszontagh 1 bulan lalu
induk
melakukan
6081ff18ee
1 mengubah file dengan 19 tambahan dan 3 penghapusan
  1. 19 3
      src/webserver/api/workflow_controller.cpp

+ 19 - 3
src/webserver/api/workflow_controller.cpp

@@ -214,6 +214,14 @@ void WorkflowController::updateWorkflow(const httplib::Request& req, httplib::Re
 
         // Note: updatedAt is managed by database automatically
 
+        // Remember the current run state so the reconciliation below can tell
+        // whether this update actually flipped it.
+        bool was_active = false;
+        auto before = storage_.get("workflows", id);
+        if (before.ok()) {
+            was_active = before.value().value("active", false);
+        }
+
         auto result = storage_.update("workflows", id, body, 0, true);
         if (result.failed()) {
             sendError(res, result.error().message(), 404);
@@ -223,9 +231,17 @@ void WorkflowController::updateWorkflow(const httplib::Request& req, httplib::Re
         // Get updated workflow
         auto workflow = storage_.get("workflows", id);
         if (workflow.ok()) {
-            // If workflow is active, update scheduler registration
-            if (workflow.value().value("active", false)) {
-                updateScheduledTriggers(id, true);
+            // Reconcile the scheduler in both directions. Registering on active
+            // but never unregistering on inactive let the stored flag and the
+            // scheduler drift apart, leaving a deactivated workflow still firing.
+            const bool is_active = workflow.value().value("active", false);
+            updateScheduledTriggers(id, is_active);
+
+            // Emit the same lifecycle events as the activate/deactivate endpoints,
+            // so a client updating the flag this way is not invisible to listeners.
+            if (is_active != was_active) {
+                ws_server_.broadcast(is_active ? "workflows.activated" : "workflows.deactivated",
+                                     {{"id", id}});
             }
 
             ws_server_.broadcast("workflows.updated", workflow.value());