feat: playbook执行日志实时流式推送(SSE) + 任务详情显示原始日志
This commit is contained in:
@@ -703,12 +703,45 @@ func (s *AnsibleService) runPlaybook(task *models.TaskExecution, playbookPath st
|
||||
cmd = exec.CommandContext(ctx, "ansible-playbook", args...)
|
||||
}
|
||||
|
||||
var output bytes.Buffer
|
||||
cmd.Stdout = &output
|
||||
cmd.Stderr = &output
|
||||
// 实时写入日志的 Writer
|
||||
sw := &syncWriter{buf: bytes.NewBuffer(nil)}
|
||||
cmd.Stdout = sw
|
||||
cmd.Stderr = sw
|
||||
|
||||
// 启动 goroutine 实时搬运日志到 task.Output
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
ticker := time.NewTicker(200 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
var lastLen int
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
s.taskLock.Lock()
|
||||
sw.mu.Lock()
|
||||
currentLen := sw.buf.Len()
|
||||
if currentLen > lastLen {
|
||||
task.Output = sw.buf.String()
|
||||
lastLen = currentLen
|
||||
}
|
||||
sw.mu.Unlock()
|
||||
s.taskLock.Unlock()
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err := cmd.Run()
|
||||
close(done) // 通知 goroutine 退出
|
||||
|
||||
// 最终同步一次完整日志
|
||||
sw.mu.Lock()
|
||||
finalOutput := sw.buf.String()
|
||||
sw.mu.Unlock()
|
||||
|
||||
s.taskLock.Lock()
|
||||
task.Output = finalOutput
|
||||
task.EndTime = time.Now()
|
||||
if err != nil {
|
||||
task.Status = "failed"
|
||||
@@ -716,7 +749,25 @@ func (s *AnsibleService) runPlaybook(task *models.TaskExecution, playbookPath st
|
||||
} else {
|
||||
task.Status = "success"
|
||||
}
|
||||
task.Output = output.String()
|
||||
s.taskLock.Unlock()
|
||||
}
|
||||
|
||||
// syncWriter 线程安全的 Writer
|
||||
type syncWriter struct {
|
||||
buf *bytes.Buffer
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (w *syncWriter) Write(p []byte) (n int, err error) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
return w.buf.Write(p)
|
||||
}
|
||||
|
||||
func (w *syncWriter) String() string {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
return w.buf.String()
|
||||
}
|
||||
|
||||
// ListPlaybooks 列出可用Playbooks
|
||||
|
||||
Reference in New Issue
Block a user