New JobQueue worker

This commit is contained in:
Jamie Curnow
2022-07-15 08:52:38 +10:00
parent 3c0af95468
commit f51c12ed9a
10 changed files with 209 additions and 103 deletions

View File

@ -0,0 +1,46 @@
package jobqueue
import (
"context"
"errors"
)
var (
ctx context.Context
cancel context.CancelFunc
worker *Worker
)
// Start ...
func Start() {
ctx, cancel = context.WithCancel(context.Background())
q := &Queue{
jobs: make(chan Job),
ctx: ctx,
cancel: cancel,
}
// Defines a queue worker, which will execute our queue.
worker = newWorker(q)
// Execute jobs in queue.
go worker.doWork()
}
// AddJob adds a job to the queue for processing
func AddJob(j Job) error {
if worker == nil {
return errors.New("Unable to add job, jobqueue has not been started")
}
worker.Queue.AddJob(j)
return nil
}
// Shutdown ...
func Shutdown() error {
if cancel == nil {
return errors.New("Unable to shutdown, jobqueue has not been started")
}
cancel()
return nil
}

View File

@ -0,0 +1,58 @@
package jobqueue
import (
"context"
"log"
"sync"
)
// Queue holds name, list of jobs and context with cancel.
type Queue struct {
jobs chan Job
ctx context.Context
cancel context.CancelFunc
}
// Job - holds logic to perform some operations during queue execution.
type Job struct {
Name string
Action func() error // A function that should be executed when the job is running.
}
// AddJobs adds jobs to the queue and cancels channel.
func (q *Queue) AddJobs(jobs []Job) {
var wg sync.WaitGroup
wg.Add(len(jobs))
for _, job := range jobs {
// Goroutine which adds job to the queue.
go func(job Job) {
q.AddJob(job)
wg.Done()
}(job)
}
go func() {
wg.Wait()
// Cancel queue channel, when all goroutines were done.
q.cancel()
}()
}
// AddJob sends job to the channel.
func (q *Queue) AddJob(job Job) {
q.jobs <- job
log.Printf("New job %s added to queue", job.Name)
}
// Run performs job execution.
func (j Job) Run() error {
log.Printf("Job running: %s", j.Name)
err := j.Action()
if err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,36 @@
package jobqueue
import (
"fmt"
"npm/internal/logger"
)
// Worker responsible for queue serving.
type Worker struct {
Queue *Queue
}
func newWorker(queue *Queue) *Worker {
return &Worker{
Queue: queue,
}
}
// doWork processes jobs from the queue (jobs channel).
func (w *Worker) doWork() bool {
for {
select {
// if context was canceled.
case <-w.Queue.ctx.Done():
logger.Info("JobQueue worker graceful shutdown")
return true
// if job received.
case job := <-w.Queue.jobs:
err := job.Run()
if err != nil {
logger.Error(fmt.Sprintf("%sError", job.Name), err)
continue
}
}
}
}