feat(backend): add in-memory collect job manager and mock executor
This commit is contained in:
168
internal/server/job_manager.go
Normal file
168
internal/server/job_manager.go
Normal file
@@ -0,0 +1,168 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type JobManager struct {
|
||||
mu sync.RWMutex
|
||||
jobs map[string]*Job
|
||||
}
|
||||
|
||||
func NewJobManager() *JobManager {
|
||||
return &JobManager{
|
||||
jobs: make(map[string]*Job),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *JobManager) CreateJob(req CollectRequest) *Job {
|
||||
now := time.Now().UTC()
|
||||
job := &Job{
|
||||
ID: generateJobID(),
|
||||
Status: CollectStatusQueued,
|
||||
Progress: 0,
|
||||
Logs: []string{"Задача поставлена в очередь"},
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
RequestMeta: CollectRequestMeta{
|
||||
Host: req.Host,
|
||||
Protocol: req.Protocol,
|
||||
Port: req.Port,
|
||||
Username: req.Username,
|
||||
AuthType: req.AuthType,
|
||||
TLSMode: req.TLSMode,
|
||||
},
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
m.jobs[job.ID] = job
|
||||
m.mu.Unlock()
|
||||
|
||||
return cloneJob(job)
|
||||
}
|
||||
|
||||
func (m *JobManager) GetJob(id string) (*Job, bool) {
|
||||
m.mu.RLock()
|
||||
job, ok := m.jobs[id]
|
||||
m.mu.RUnlock()
|
||||
if !ok || job == nil {
|
||||
return nil, false
|
||||
}
|
||||
return cloneJob(job), true
|
||||
}
|
||||
|
||||
func (m *JobManager) CancelJob(id string) (*Job, bool) {
|
||||
m.mu.Lock()
|
||||
job, ok := m.jobs[id]
|
||||
if !ok || job == nil {
|
||||
m.mu.Unlock()
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if !isTerminalCollectStatus(job.Status) {
|
||||
job.Status = CollectStatusCanceled
|
||||
job.Error = ""
|
||||
job.UpdatedAt = time.Now().UTC()
|
||||
job.Logs = append(job.Logs, "Сбор отменен пользователем")
|
||||
}
|
||||
|
||||
cancelFn := job.cancel
|
||||
job.cancel = nil
|
||||
cloned := cloneJob(job)
|
||||
m.mu.Unlock()
|
||||
|
||||
if cancelFn != nil {
|
||||
cancelFn()
|
||||
}
|
||||
|
||||
return cloned, true
|
||||
}
|
||||
|
||||
func (m *JobManager) UpdateJobStatus(id, status string, progress int, errMsg string) (*Job, bool) {
|
||||
m.mu.Lock()
|
||||
job, ok := m.jobs[id]
|
||||
if !ok || job == nil {
|
||||
m.mu.Unlock()
|
||||
return nil, false
|
||||
}
|
||||
if isTerminalCollectStatus(job.Status) {
|
||||
cloned := cloneJob(job)
|
||||
m.mu.Unlock()
|
||||
return cloned, true
|
||||
}
|
||||
|
||||
job.Status = status
|
||||
job.Progress = normalizeProgress(progress)
|
||||
job.Error = errMsg
|
||||
job.UpdatedAt = time.Now().UTC()
|
||||
if isTerminalCollectStatus(status) {
|
||||
job.cancel = nil
|
||||
}
|
||||
|
||||
cloned := cloneJob(job)
|
||||
m.mu.Unlock()
|
||||
return cloned, true
|
||||
}
|
||||
|
||||
func (m *JobManager) AppendJobLog(id, message string) (*Job, bool) {
|
||||
if message == "" {
|
||||
return m.GetJob(id)
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
job, ok := m.jobs[id]
|
||||
if !ok || job == nil {
|
||||
m.mu.Unlock()
|
||||
return nil, false
|
||||
}
|
||||
|
||||
job.Logs = append(job.Logs, message)
|
||||
job.UpdatedAt = time.Now().UTC()
|
||||
|
||||
cloned := cloneJob(job)
|
||||
m.mu.Unlock()
|
||||
return cloned, true
|
||||
}
|
||||
|
||||
func (m *JobManager) AttachJobCancel(id string, cancelFn context.CancelFunc) bool {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
job, ok := m.jobs[id]
|
||||
if !ok || job == nil || isTerminalCollectStatus(job.Status) {
|
||||
return false
|
||||
}
|
||||
job.cancel = cancelFn
|
||||
return true
|
||||
}
|
||||
|
||||
func isTerminalCollectStatus(status string) bool {
|
||||
switch status {
|
||||
case CollectStatusSuccess, CollectStatusFailed, CollectStatusCanceled:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeProgress(progress int) int {
|
||||
if progress < 0 {
|
||||
return 0
|
||||
}
|
||||
if progress > 100 {
|
||||
return 100
|
||||
}
|
||||
return progress
|
||||
}
|
||||
|
||||
func cloneJob(job *Job) *Job {
|
||||
if job == nil {
|
||||
return nil
|
||||
}
|
||||
cloned := *job
|
||||
cloned.Logs = append([]string(nil), job.Logs...)
|
||||
cloned.cancel = nil
|
||||
return &cloned
|
||||
}
|
||||
Reference in New Issue
Block a user