diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..ebb780f --- /dev/null +++ b/errors.go @@ -0,0 +1,7 @@ +package slowdo + +import "errors" + +var ( + ErrWaitTimeTooShort = errors.New("wait time too short") +) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..448bcc4 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/fumiama/slowdo + +go 1.22.1 diff --git a/job.go b/job.go new file mode 100644 index 0000000..1151e04 --- /dev/null +++ b/job.go @@ -0,0 +1,58 @@ +package slowdo + +import ( + "sync" + "time" +) + +type Job[item any] struct { + maxmait time.Duration + commit func([]item) + itemmu sync.Mutex + items []item + timer *time.Timer +} + +func NewJob[item any]( + maxwait time.Duration, commit func([]item), +) (*Job[item], error) { + if maxwait <= time.Millisecond { + return nil, ErrWaitTimeTooShort + } + return &Job[item]{ + maxmait: maxwait, + commit: commit, + }, nil +} + +func (jb *Job[item]) Add(it item) { + jb.itemmu.Lock() + defer jb.itemmu.Unlock() + if len(jb.items) == 0 { + defer jb.collect() + } + jb.items = append(jb.items, it) +} + +func (jb *Job[item]) Commit() { + jb.itemmu.Lock() + if jb.timer != nil { + jb.timer.Stop() + jb.timer = nil + } + if len(jb.items) == 0 { + jb.itemmu.Unlock() + return + } + itemscp := make([]item, len(jb.items)) + copy(itemscp, jb.items) + jb.items = jb.items[:0] + jb.itemmu.Unlock() + jb.commit(itemscp) +} + +func (jb *Job[item]) collect() { + jb.itemmu.Lock() + defer jb.itemmu.Unlock() + jb.timer = time.AfterFunc(jb.maxmait, jb.Commit) +}