feat: Task Health Check + customer_number in webhook payload
- Task model: CustomerNumber field (K-Nummer aus customers.number)
- DB: taskSelectCols joined c.number, scanTask scans CustomerNumber
- Hub: WaitForAgentOnline() polls until agent reconnects or timeout
- Scheduler: executeUpdateWithHealthCheck() waits for agent reconnect after update
- health_check: {agent_online: bool, checked_at: RFC3339} in result
- Status: completed_with_warning wenn Update OK aber Agent offline bleibt
- Frontend: Task-Tabelle zeigt Status-Badge (lauft/fehler/warnung/abgebr.)
This commit is contained in:
@@ -62,22 +62,40 @@ func (s *TaskScheduler) executeTask(task models.Task) {
|
||||
case "backup":
|
||||
result, taskErr = s.executeBackup(task.AgentID)
|
||||
case "update":
|
||||
result, taskErr = s.executeUpdate(task.AgentID, task.Reboot)
|
||||
result, taskErr = s.executeUpdateWithHealthCheck(task.AgentID, task.Reboot, task.HealthCheck, task.HealthCheckTimeout)
|
||||
default:
|
||||
taskErr = fmt.Errorf("unbekannte Aktion: %s", task.Action)
|
||||
}
|
||||
|
||||
success := taskErr == nil
|
||||
healthCheckWarning := false
|
||||
if !success {
|
||||
result = map[string]string{"error": taskErr.Error()}
|
||||
// Check if it's a health check warning (update ran OK but agent didn't come back)
|
||||
if resultMap, ok := result.(map[string]interface{}); ok {
|
||||
if hc, ok := resultMap["health_check"].(map[string]interface{}); ok {
|
||||
if online, ok := hc["agent_online"].(bool); ok && !online {
|
||||
healthCheckWarning = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !healthCheckWarning {
|
||||
result = map[string]string{"error": taskErr.Error()}
|
||||
}
|
||||
log.Printf("Scheduler: Task #%d fehlgeschlagen: %v", task.ID, taskErr)
|
||||
} else {
|
||||
log.Printf("Scheduler: Task #%d erfolgreich abgeschlossen", task.ID)
|
||||
}
|
||||
|
||||
// Use CompleteRecurringTask for proper recurring handling
|
||||
// Health check warnings count as success for recurring schedule, but status = "completed_with_warning"
|
||||
scheduleSuccess := success || healthCheckWarning
|
||||
s.db.CompleteRecurringTask(task.ID, task.ScheduleType, task.ScheduleTime,
|
||||
task.ScheduleWeekday, task.ScheduleMonthday, success, result)
|
||||
task.ScheduleWeekday, task.ScheduleMonthday, scheduleSuccess, result)
|
||||
|
||||
// Override status for health check warnings
|
||||
if healthCheckWarning {
|
||||
s.db.UpdateTaskStatusDirect(task.ID, "completed_with_warning")
|
||||
}
|
||||
|
||||
// Re-read task for webhook payload
|
||||
fullTask, _ := s.db.GetTask(task.ID)
|
||||
@@ -156,6 +174,10 @@ func (s *TaskScheduler) executeBackup(agentID string) (interface{}, error) {
|
||||
}
|
||||
|
||||
func (s *TaskScheduler) executeUpdate(agentID string, reboot bool) (interface{}, error) {
|
||||
return s.executeUpdateWithHealthCheck(agentID, reboot, false, 600)
|
||||
}
|
||||
|
||||
func (s *TaskScheduler) executeUpdateWithHealthCheck(agentID string, reboot bool, healthCheck bool, healthCheckTimeout int) (interface{}, error) {
|
||||
if !s.hub.IsAgentConnected(agentID) {
|
||||
return nil, fmt.Errorf("Agent nicht verbunden")
|
||||
}
|
||||
@@ -201,6 +223,7 @@ func (s *TaskScheduler) executeUpdate(agentID string, reboot bool) (interface{},
|
||||
return nil, fmt.Errorf("Update-Command senden fehlgeschlagen: %w", err)
|
||||
}
|
||||
|
||||
var updateResult map[string]interface{}
|
||||
select {
|
||||
case resp := <-updateCh:
|
||||
respStatus, _ := resp["status"].(string)
|
||||
@@ -208,15 +231,48 @@ func (s *TaskScheduler) executeUpdate(agentID string, reboot bool) (interface{},
|
||||
errMsg, _ := resp["error"].(string)
|
||||
return resp, fmt.Errorf("Update fehlgeschlagen: %s", errMsg)
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"message": "Update ausgefuehrt",
|
||||
"check_result": checkResult,
|
||||
"update_result": resp,
|
||||
"reboot": reboot,
|
||||
}, nil
|
||||
updateResult = resp
|
||||
case <-time.After(900 * time.Second):
|
||||
return nil, fmt.Errorf("Timeout beim Update")
|
||||
}
|
||||
|
||||
result := map[string]interface{}{
|
||||
"message": "Update ausgefuehrt",
|
||||
"check_result": checkResult,
|
||||
"update_result": updateResult,
|
||||
"reboot": reboot,
|
||||
}
|
||||
|
||||
// Health Check: wait for agent to come back online
|
||||
if healthCheck {
|
||||
timeout := time.Duration(healthCheckTimeout) * time.Second
|
||||
if timeout <= 0 {
|
||||
timeout = 600 * time.Second
|
||||
}
|
||||
log.Printf("Scheduler: Health Check fuer Agent %s (Timeout: %v)", agentID, timeout)
|
||||
|
||||
// If no reboot, agent should still be connected — give it a moment for post-update restart
|
||||
if !reboot {
|
||||
time.Sleep(15 * time.Second)
|
||||
}
|
||||
|
||||
checkedAt := time.Now().UTC().Format(time.RFC3339)
|
||||
agentOnline := s.hub.WaitForAgentOnline(agentID, timeout)
|
||||
result["health_check"] = map[string]interface{}{
|
||||
"agent_online": agentOnline,
|
||||
"checked_at": checkedAt,
|
||||
}
|
||||
|
||||
if !agentOnline {
|
||||
result["message"] = "Update ausgefuehrt, aber Agent nicht wieder online (Health Check fehlgeschlagen)"
|
||||
log.Printf("Scheduler: Health Check fehlgeschlagen — Agent %s nach %v nicht online", agentID, timeout)
|
||||
// Return result but signal warning via error
|
||||
return result, fmt.Errorf("Health Check: Agent nach %v nicht online", timeout)
|
||||
}
|
||||
log.Printf("Scheduler: Health Check OK — Agent %s wieder online", agentID)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *TaskScheduler) sendWebhook(taskID int, url string, task interface{}) {
|
||||
|
||||
Reference in New Issue
Block a user