Commit 4b038578 authored by ale's avatar ale

Give every job a random ID and make it part of the interface

parent c0672e48
...@@ -16,15 +16,31 @@ import ( ...@@ -16,15 +16,31 @@ import (
// unique). It's basically a glorified goroutine wrapper with a // unique). It's basically a glorified goroutine wrapper with a
// cancelable Context. // cancelable Context.
type Job interface { type Job interface {
ID() string
RunContext(context.Context) error RunContext(context.Context) error
Cancel() Cancel()
Wait() error Wait() error
} }
// Give a job its own random unique ID.
type idJob struct {
Job
id string
}
func (j *idJob) ID() string { return j.id }
// WithID gives a job a random unique ID.
func WithID(j Job) Job {
return &idJob{
Job: j,
id: util.RandomID(),
}
}
// Adds a Cancel method to a job. // Adds a Cancel method to a job.
type cancelableJob struct { type cancelableJob struct {
Job Job
done chan struct{} done chan struct{}
err error err error
cancelMx sync.Mutex cancelMx sync.Mutex
...@@ -74,11 +90,12 @@ type funcJob struct { ...@@ -74,11 +90,12 @@ type funcJob struct {
// JobFunc creates a new cancelable Job that wraps a function call. // JobFunc creates a new cancelable Job that wraps a function call.
func JobFunc(fn func(context.Context) error) Job { func JobFunc(fn func(context.Context) error) Job {
return WithCancel(&funcJob{ return WithCancel(WithID(&funcJob{
fn: fn, fn: fn,
}) }))
} }
func (j *funcJob) ID() string { return "" }
func (j *funcJob) Cancel() {} func (j *funcJob) Cancel() {}
func (j *funcJob) Wait() error { return errors.New("Wait not implemented") } func (j *funcJob) Wait() error { return errors.New("Wait not implemented") }
...@@ -269,12 +286,12 @@ func NewStateManager() *StateManager { ...@@ -269,12 +286,12 @@ func NewStateManager() *StateManager {
} }
} }
func (m *StateManager) setStatusPending(id, name string, j Job) { func (m *StateManager) setStatusPending(name string, j Job) {
m.mx.Lock() m.mx.Lock()
defer m.mx.Unlock() defer m.mx.Unlock()
m.pending[id] = &Status{ m.pending[j.ID()] = &Status{
ID: id, ID: j.ID(),
Name: name, Name: name,
Status: JobStatusPending, Status: JobStatusPending,
Job: j, Job: j,
...@@ -313,10 +330,9 @@ func (m *StateManager) setStatusDone(id string, err error) { ...@@ -313,10 +330,9 @@ func (m *StateManager) setStatusDone(id string, err error) {
func (m *StateManager) WithStatus(j Job, name string) Job { func (m *StateManager) WithStatus(j Job, name string) Job {
sj := &statusJob{ sj := &statusJob{
Job: j, Job: j,
id: util.RandomID(),
mgr: m, mgr: m,
} }
m.setStatusPending(sj.id, name, sj) m.setStatusPending(name, sj)
return sj return sj
} }
...@@ -349,14 +365,13 @@ func (m *StateManager) GetStatus() ([]Status, []Status, []Status) { ...@@ -349,14 +365,13 @@ func (m *StateManager) GetStatus() ([]Status, []Status, []Status) {
type statusJob struct { type statusJob struct {
Job Job
id string
mgr *StateManager mgr *StateManager
} }
func (j *statusJob) RunContext(ctx context.Context) error { func (j *statusJob) RunContext(ctx context.Context) error {
j.mgr.setStatusRunning(j.id) j.mgr.setStatusRunning(j.ID())
err := j.Job.RunContext(ctx) err := j.Job.RunContext(ctx)
j.mgr.setStatusDone(j.id, err) j.mgr.setStatusDone(j.ID(), err)
return err return err
} }
......
package util
import (
crand "crypto/rand"
"encoding/binary"
"encoding/hex"
"math/rand"
)
var rndID *rand.Rand
func init() {
seed, _ := RandomSeed()
rndID = rand.New(rand.NewSource(seed))
}
// RandomID generates a random unique ID. It will return an identifier
// consisting of 32 ascii-friendly bytes (16 random bytes,
// hex-encoded).
func RandomID() string {
var b [16]byte
binary.LittleEndian.PutUint64(b[:8], rndID.Uint64())
binary.LittleEndian.PutUint64(b[8:16], rndID.Uint64())
return hex.EncodeToString(b[:])
}
// Generate a random int64, and return it along with its byte
// representation (encoding/binary, little-endian).
func RandomSeed() (int64, []byte) {
// Initialize the seed from a secure source.
var b [8]byte
if _, err := crand.Read(b[:]); err != nil { // nolint: gosec
panic(err)
}
seed := binary.LittleEndian.Uint64(b[:])
return int64(seed), b[:]
}
package util package util
import ( import (
"crypto/rand"
"encoding/hex"
"strings" "strings"
) )
...@@ -43,14 +41,3 @@ func (m *MultiError) OrNil() error { ...@@ -43,14 +41,3 @@ func (m *MultiError) OrNil() error {
func (m *MultiError) IsNil() bool { func (m *MultiError) IsNil() bool {
return len(m.errors) == 0 return len(m.errors) == 0
} }
// RandomID generates a random unique ID. It will return an identifier
// consisting of 32 ascii-friendly bytes (16 random bytes,
// hex-encoded).
func RandomID() string {
var b [16]byte
if _, err := rand.Read(b[:]); err != nil { // nolint: gosec
panic(err)
}
return hex.EncodeToString(b[:])
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment