sched/job/job.go
Sherif Abdel-Naby 3bdc2adc71 Add README.md 🚀 + Small Tweaks
Signed-off-by: Sherif Abdel-Naby <sherifabdlnaby@gmail.com>
2021-04-10 15:08:27 +02:00

124 lines
2.4 KiB
Go

package job
import (
"fmt"
"sync"
"time"
"github.com/google/uuid"
)
//Job Wraps JobFun and provide:
// 1. Creation, Start, and Finish Time
// 2. Recover From Panics
type Job struct {
id string
jobFunc func()
createTime time.Time
startTime time.Time
finishTime time.Time
state State
mx sync.RWMutex
}
//State Return Job current state.
func (j *Job) State() State {
j.mx.RLock()
defer j.mx.RUnlock()
return j.state
}
//NewJobWithID Create new Job with the supplied Id.
func NewJobWithID(id string, jobFunc func()) *Job {
return &Job{
id: id,
jobFunc: jobFunc,
createTime: time.Now(),
startTime: time.Time{},
finishTime: time.Time{},
state: NEW,
}
}
//NewJob Create new Job, id is assigned a UUID instead.
func NewJob(jobFunc func()) *Job {
return NewJobWithID(uuid.New().String(), jobFunc)
}
//ID Return Job ID
func (j *Job) ID() string {
return j.id
}
//ActualElapsed Return the actual time of procession of Job.
// Return -1 if job hasn't started yet.
func (j *Job) ActualElapsed() time.Duration {
j.mx.RLock()
defer j.mx.RUnlock()
if !j.startTime.IsZero() {
if j.finishTime.IsZero() {
return time.Since(j.startTime)
}
return j.finishTime.Sub(j.startTime)
}
return -1
}
//TotalElapsed Returns the total time between creation of object and finishing processing its job.
// Return -1 if job hasn't started yet.
func (j *Job) TotalElapsed() time.Duration {
j.mx.RLock()
defer j.mx.RUnlock()
if !j.startTime.IsZero() {
if j.finishTime.IsZero() {
return time.Since(j.createTime)
}
return j.finishTime.Sub(j.createTime)
}
return -1
}
//Run Run the internal Job (synchronous)
func (j *Job) Run() error {
return j.run()
}
func (j *Job) run() (err error) {
j.mx.Lock()
if j.state != NEW {
if j.state == RUNNING {
err = ErrorJobStarted{Message: "job already started"}
} else {
err = ErrorJobStarted{Message: "job finished execution"}
}
j.mx.Unlock()
return err
}
// Handle Panics and set correct state
defer func() {
j.mx.Lock()
// TODO handle panics
if r := recover(); r != nil {
err = ErrorJobPanic{Message: fmt.Sprintf("job panicked: %v", r)}
j.state = PANICKED
} else {
j.state = FINISHED
}
j.finishTime = time.Now()
j.mx.Unlock()
}()
j.state = RUNNING
j.startTime = time.Now()
// Unlock State
j.mx.Unlock()
// Run Job
j.jobFunc()
return nil
}