package heroagent import ( "context" "fmt" "log" "sync" "time" ) // JobStatus represents the status of a job type JobStatus string const ( // JobStatusNew indicates a newly created job JobStatusNew JobStatus = "new" // JobStatusActive indicates a job that is currently being processed JobStatusActive JobStatus = "active" // JobStatusError indicates a job that encountered an error JobStatusError JobStatus = "error" // JobStatusDone indicates a job that has been completed successfully JobStatusDone JobStatus = "done" ) // Job represents a job to be processed type Job struct { JobID uint32 `json:"jobid"` Topic string `json:"topic"` Params string `json:"params"` Status JobStatus `json:"status"` TimeScheduled int64 `json:"time_scheduled"` TimeStart int64 `json:"time_start"` TimeEnd int64 `json:"time_end"` Error string `json:"error"` Result string `json:"result"` } // RedisConnection wraps Redis connection details type RedisConnection struct { TCPPort int UnixSocketPath string } // JobWorker represents a worker that processes jobs type JobWorker struct { id int jobMgr *JobManager ctx context.Context wg *sync.WaitGroup } // run is the main worker loop func (w *JobWorker) run() { log.Printf("Worker %d started", w.id) ticker := time.NewTicker(w.jobMgr.config.QueuePollInterval) defer ticker.Stop() for { select { case <-w.ctx.Done(): log.Printf("Worker %d stopping", w.id) return case <-ticker.C: // Check for jobs in Redis if err := w.checkForJobs(); err != nil { log.Printf("Worker %d error checking for jobs: %v", w.id, err) } } } } // checkForJobs checks for jobs in Redis func (w *JobWorker) checkForJobs() error { // Get list of queues queues, err := w.jobMgr.redisMgr.ListQueues() if err != nil { return fmt.Errorf("failed to list queues: %w", err) } // Check each queue for jobs for _, topic := range queues { // Try to fetch a job from the queue job, err := w.jobMgr.redisMgr.FetchNextJob(topic) if err != nil { // If queue is empty, continue to next queue continue } // Process the job if err := w.processJob(job); err != nil { log.Printf("Error processing job %d: %v", job.JobID, err) } // Only process one job at a time return nil } return nil } // processJob processes a job func (w *JobWorker) processJob(job *Job) error { log.Printf("Worker %d processing job %d", w.id, job.JobID) // Update job status to active job.Status = JobStatusActive job.TimeStart = time.Now().Unix() // Update job in both OurDB and Redis if err := w.jobMgr.updateJobInBothStores(job); err != nil { return fmt.Errorf("failed to update job status: %w", err) } // Simulate job processing // In a real implementation, this would execute the job based on its parameters time.Sleep(1 * time.Second) // Complete the job job.Status = JobStatusDone job.TimeEnd = time.Now().Unix() job.Result = fmt.Sprintf("Job %d processed successfully", job.JobID) // Update job in OurDB and remove from Redis if err := w.jobMgr.completeJobProcessing(job); err != nil { return fmt.Errorf("failed to complete job: %w", err) } log.Printf("Worker %d completed job %d", w.id, job.JobID) return nil }