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 (
// unique). It's basically a glorified goroutine wrapper with a
// cancelable Context.
type Job interface {
ID() string
RunContext(context.Context) error
Cancel()
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.
type cancelableJob struct {
Job
done chan struct{}
err error
cancelMx sync.Mutex
......@@ -74,11 +90,12 @@ type funcJob struct {
// JobFunc creates a new cancelable Job that wraps a function call.
func JobFunc(fn func(context.Context) error) Job {
return WithCancel(&funcJob{
return WithCancel(WithID(&funcJob{
fn: fn,
})
}))
}
func (j *funcJob) ID() string { return "" }
func (j *funcJob) Cancel() {}
func (j *funcJob) Wait() error { return errors.New("Wait not implemented") }
......@@ -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()
defer m.mx.Unlock()
m.pending[id] = &Status{
ID: id,
m.pending[j.ID()] = &Status{
ID: j.ID(),
Name: name,
Status: JobStatusPending,
Job: j,
......@@ -313,10 +330,9 @@ func (m *StateManager) setStatusDone(id string, err error) {
func (m *StateManager) WithStatus(j Job, name string) Job {
sj := &statusJob{
Job: j,
id: util.RandomID(),
mgr: m,
}
m.setStatusPending(sj.id, name, sj)
m.setStatusPending(name, sj)
return sj
}
......@@ -349,14 +365,13 @@ func (m *StateManager) GetStatus() ([]Status, []Status, []Status) {
type statusJob struct {
Job
id string
mgr *StateManager
}
func (j *statusJob) RunContext(ctx context.Context) error {
j.mgr.setStatusRunning(j.id)
j.mgr.setStatusRunning(j.ID())
err := j.Job.RunContext(ctx)
j.mgr.setStatusDone(j.id, err)
j.mgr.setStatusDone(j.ID(), 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
import (
"crypto/rand"
"encoding/hex"
"strings"
)
......@@ -43,14 +41,3 @@ func (m *MultiError) OrNil() error {
func (m *MultiError) IsNil() bool {
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