Просмотр исходного кода

feat: record which runner produced an execution

runnerId was already in the executions view's field list and in the API
response, but nothing ever wrote it, so it was null on every row and a Runner
column would have been permanently empty.

The workflow engine had no idea which runner it belonged to. Its config now
carries the runner id, the runner service passes its own in, and every
execution records it. The executions list shows it alongside the trigger, so a
run can be attributed to a runner without reading logs.

Verified: an execution produced after the change reports runner-1, while
earlier ones remain null.
fszontagh 1 месяц назад
Родитель
Сommit
905ad798f8

+ 1 - 0
src/runner/runner_service.cpp

@@ -321,6 +321,7 @@ RunnerService::RunnerService(const RunnerServiceConfig& config)
 
 
     // Initialize workflow engine
     // Initialize workflow engine
     config_.workflow_engine_config.max_concurrent_executions = config_.max_concurrent_executions;
     config_.workflow_engine_config.max_concurrent_executions = config_.max_concurrent_executions;
+    config_.workflow_engine_config.runner_id = config_.runner_id;
     engine_ = std::make_unique<WorkflowEngine>(*registry_, *storage_, config_.workflow_engine_config);
     engine_ = std::make_unique<WorkflowEngine>(*registry_, *storage_, config_.workflow_engine_config);
 
 
     // Set up credential auth callback for workflow engine
     // Set up credential auth callback for workflow engine

+ 2 - 0
src/runner/workflow_engine.cpp

@@ -111,6 +111,7 @@ nlohmann::json ExecutionResult::toJson() const {
     // Note: id is managed by database as _id (execution_id is passed to storage_.insert)
     // Note: id is managed by database as _id (execution_id is passed to storage_.insert)
     j["workflowId"] = workflow_id;
     j["workflowId"] = workflow_id;
     j["workflowName"] = workflow_name;
     j["workflowName"] = workflow_name;
+    j["runnerId"] = runner_id;
     j["status"] = executionStatusToString(status);
     j["status"] = executionStatusToString(status);
     j["triggerType"] = trigger_type;
     j["triggerType"] = trigger_type;
     j["triggerData"] = truncateLargeValues(trigger_data);
     j["triggerData"] = truncateLargeValues(trigger_data);
@@ -199,6 +200,7 @@ Result<ExecutionResult> WorkflowEngine::execute(const Workflow& workflow,
     // Create execution record
     // Create execution record
     ExecutionResult result;
     ExecutionResult result;
     result.execution_id = UUID::generatePrefixed("exec");
     result.execution_id = UUID::generatePrefixed("exec");
+    result.runner_id = config_.runner_id;
     result.workflow_id = workflow.id;
     result.workflow_id = workflow.id;
     result.workflow_name = workflow.name;
     result.workflow_name = workflow.name;
     result.status = ExecutionStatus::Running;
     result.status = ExecutionStatus::Running;

+ 4 - 0
src/runner/workflow_engine.hpp

@@ -88,6 +88,7 @@ struct ExecutionResult {
     std::string execution_id;
     std::string execution_id;
     std::string workflow_id;
     std::string workflow_id;
     std::string workflow_name;
     std::string workflow_name;
+    std::string runner_id;
     ExecutionStatus status = ExecutionStatus::Pending;
     ExecutionStatus status = ExecutionStatus::Pending;
     std::string trigger_type;
     std::string trigger_type;
     nlohmann::json trigger_data;
     nlohmann::json trigger_data;
@@ -107,6 +108,9 @@ using ExecutionCallback = std::function<void(const std::string& event,
 
 
 // Workflow engine configuration
 // Workflow engine configuration
 struct WorkflowEngineConfig {
 struct WorkflowEngineConfig {
+    // Recorded on every execution this engine runs, so a stored execution says
+    // which runner produced it.
+    std::string runner_id;
     int64_t default_timeout_ms = 60000;
     int64_t default_timeout_ms = 60000;
     int max_concurrent_executions = 10;
     int max_concurrent_executions = 10;
     size_t script_engine_pool_size = 4;
     size_t script_engine_pool_size = 4;

+ 2 - 0
webui/src/api/workflows.ts

@@ -288,6 +288,7 @@ export interface ExecutionListItem {
   workflowName: string
   workflowName: string
   status: string
   status: string
   triggerType: string
   triggerType: string
+  runnerId: string
   error: string
   error: string
   startedAt: number
   startedAt: number
   finishedAt: number
   finishedAt: number
@@ -301,6 +302,7 @@ function transformExecutionListItem(data: any): ExecutionListItem {
     workflowName: data.workflowName,
     workflowName: data.workflowName,
     status: data.status,
     status: data.status,
     triggerType: data.triggerType || '',
     triggerType: data.triggerType || '',
+    runnerId: data.runnerId || '',
     error: data.error || '',
     error: data.error || '',
     startedAt: data.startedAt,
     startedAt: data.startedAt,
     finishedAt: data.finishedAt,
     finishedAt: data.finishedAt,

+ 6 - 0
webui/src/pages/ExecutionsPage.tsx

@@ -114,6 +114,9 @@ export default function ExecutionsPage() {
                   <th className="px-4 py-3 text-left text-sm font-medium text-gray-600 dark:text-gray-300">
                   <th className="px-4 py-3 text-left text-sm font-medium text-gray-600 dark:text-gray-300">
                     Trigger
                     Trigger
                   </th>
                   </th>
+                  <th className="px-4 py-3 text-left text-sm font-medium text-gray-600 dark:text-gray-300">
+                    Runner
+                  </th>
                   <th className="px-4 py-3 text-left text-sm font-medium text-gray-600 dark:text-gray-300">
                   <th className="px-4 py-3 text-left text-sm font-medium text-gray-600 dark:text-gray-300">
                     Started
                     Started
                   </th>
                   </th>
@@ -160,6 +163,9 @@ export default function ExecutionsPage() {
                     <td className="px-4 py-3 align-top text-gray-600 dark:text-gray-400">
                     <td className="px-4 py-3 align-top text-gray-600 dark:text-gray-400">
                       {execution.triggerType}
                       {execution.triggerType}
                     </td>
                     </td>
+                    <td className="px-4 py-3 align-top text-gray-600 dark:text-gray-400 text-sm">
+                      {execution.runnerId || '-'}
+                    </td>
                     <td className="px-4 py-3 align-top text-gray-500 dark:text-gray-400 text-sm">
                     <td className="px-4 py-3 align-top text-gray-500 dark:text-gray-400 text-sm">
                       {execution.startedAt
                       {execution.startedAt
                         ? safeFormatDistanceToNow(execution.startedAt)
                         ? safeFormatDistanceToNow(execution.startedAt)