[bugfix] update go-cache library to fix critical bug during cache sweep scheduling (#725)
* update go-cache library to fix critical bug regarding cache sweep scheduling Signed-off-by: kim <grufwub@gmail.com> * update go-sched Signed-off-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
40f91d052c
commit
d20ec967c4
6
go.mod
6
go.mod
|
@ -6,13 +6,13 @@ require (
|
||||||
codeberg.org/gruf/go-atomics v1.1.0
|
codeberg.org/gruf/go-atomics v1.1.0
|
||||||
codeberg.org/gruf/go-bytesize v0.2.1
|
codeberg.org/gruf/go-bytesize v0.2.1
|
||||||
codeberg.org/gruf/go-byteutil v1.0.2
|
codeberg.org/gruf/go-byteutil v1.0.2
|
||||||
codeberg.org/gruf/go-cache/v2 v2.1.1
|
codeberg.org/gruf/go-cache/v2 v2.1.2
|
||||||
codeberg.org/gruf/go-debug v1.2.0
|
codeberg.org/gruf/go-debug v1.2.0
|
||||||
codeberg.org/gruf/go-errors/v2 v2.0.2
|
codeberg.org/gruf/go-errors/v2 v2.0.2
|
||||||
codeberg.org/gruf/go-kv v1.3.2
|
codeberg.org/gruf/go-kv v1.3.2
|
||||||
codeberg.org/gruf/go-logger/v2 v2.0.6
|
codeberg.org/gruf/go-logger/v2 v2.0.6
|
||||||
codeberg.org/gruf/go-mutexes v1.1.2
|
codeberg.org/gruf/go-mutexes v1.1.2
|
||||||
codeberg.org/gruf/go-runners v1.2.1
|
codeberg.org/gruf/go-runners v1.2.2
|
||||||
codeberg.org/gruf/go-store v1.3.8
|
codeberg.org/gruf/go-store v1.3.8
|
||||||
github.com/buckket/go-blurhash v1.1.0
|
github.com/buckket/go-blurhash v1.1.0
|
||||||
github.com/coreos/go-oidc/v3 v3.1.0
|
github.com/coreos/go-oidc/v3 v3.1.0
|
||||||
|
@ -62,7 +62,7 @@ require (
|
||||||
codeberg.org/gruf/go-fastpath v1.0.3 // indirect
|
codeberg.org/gruf/go-fastpath v1.0.3 // indirect
|
||||||
codeberg.org/gruf/go-hashenc v1.0.2 // indirect
|
codeberg.org/gruf/go-hashenc v1.0.2 // indirect
|
||||||
codeberg.org/gruf/go-pools v1.1.0 // indirect
|
codeberg.org/gruf/go-pools v1.1.0 // indirect
|
||||||
codeberg.org/gruf/go-sched v1.0.1 // indirect
|
codeberg.org/gruf/go-sched v1.0.4 // indirect
|
||||||
github.com/aymerick/douceur v0.2.0 // indirect
|
github.com/aymerick/douceur v0.2.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b // indirect
|
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b // indirect
|
||||||
|
|
11
go.sum
11
go.sum
|
@ -50,8 +50,8 @@ codeberg.org/gruf/go-byteutil v1.0.0/go.mod h1:cWM3tgMCroSzqoBXUXMhvxTxYJp+TbCr6
|
||||||
codeberg.org/gruf/go-byteutil v1.0.2 h1:OesVyK5VKWeWdeDR00zRJ+Oy8hjXx1pBhn7WVvcZWVE=
|
codeberg.org/gruf/go-byteutil v1.0.2 h1:OesVyK5VKWeWdeDR00zRJ+Oy8hjXx1pBhn7WVvcZWVE=
|
||||||
codeberg.org/gruf/go-byteutil v1.0.2/go.mod h1:cWM3tgMCroSzqoBXUXMhvxTxYJp+TbCr6ioISRY5vSU=
|
codeberg.org/gruf/go-byteutil v1.0.2/go.mod h1:cWM3tgMCroSzqoBXUXMhvxTxYJp+TbCr6ioISRY5vSU=
|
||||||
codeberg.org/gruf/go-cache v1.1.2/go.mod h1:/Dbc+xU72Op3hMn6x2PXF3NE9uIDFeS+sXPF00hN/7o=
|
codeberg.org/gruf/go-cache v1.1.2/go.mod h1:/Dbc+xU72Op3hMn6x2PXF3NE9uIDFeS+sXPF00hN/7o=
|
||||||
codeberg.org/gruf/go-cache/v2 v2.1.1 h1:Ate0URlO6dVTYGxcIST9sDKtwOqrqBmlm73zy3Bq1+k=
|
codeberg.org/gruf/go-cache/v2 v2.1.2 h1:MjnnsrZit4WYN4E6pZhcw3YY2QXNBRG5Ijz7z3r6z2o=
|
||||||
codeberg.org/gruf/go-cache/v2 v2.1.1/go.mod h1:XstSofaENTH3PNBoMrBcowFJ339OcJfTwO0PCOp5lKQ=
|
codeberg.org/gruf/go-cache/v2 v2.1.2/go.mod h1:bFZSpjN9cszV3ArmHW7IwvcDDn/SklfECv0U1FMRMdU=
|
||||||
codeberg.org/gruf/go-ctx v1.0.2/go.mod h1:iMyid3m2Rr1wSWL+snliBK5qE51b4pLY5CozVUrb/QU=
|
codeberg.org/gruf/go-ctx v1.0.2/go.mod h1:iMyid3m2Rr1wSWL+snliBK5qE51b4pLY5CozVUrb/QU=
|
||||||
codeberg.org/gruf/go-debug v1.2.0 h1:WBbTMnK1ArFKUmgv04aO2JiC/daTOB8zQGi521qb7OU=
|
codeberg.org/gruf/go-debug v1.2.0 h1:WBbTMnK1ArFKUmgv04aO2JiC/daTOB8zQGi521qb7OU=
|
||||||
codeberg.org/gruf/go-debug v1.2.0/go.mod h1:N+vSy9uJBQgpQcJUqjctvqFz7tBHJf+S/PIjLILzpLg=
|
codeberg.org/gruf/go-debug v1.2.0/go.mod h1:N+vSy9uJBQgpQcJUqjctvqFz7tBHJf+S/PIjLILzpLg=
|
||||||
|
@ -80,10 +80,11 @@ codeberg.org/gruf/go-nowish v1.1.2/go.mod h1:70nvICNcqQ9OHpF07N614Dyk7cpL5ToWU1K
|
||||||
codeberg.org/gruf/go-pools v1.1.0 h1:LbYP24eQLl/YI1fSU2pafiwhGol1Z1zPjRrMsXpF88s=
|
codeberg.org/gruf/go-pools v1.1.0 h1:LbYP24eQLl/YI1fSU2pafiwhGol1Z1zPjRrMsXpF88s=
|
||||||
codeberg.org/gruf/go-pools v1.1.0/go.mod h1:ZMYpt/DjQWYC3zFD3T97QWSFKs62zAUGJ/tzvgB9D68=
|
codeberg.org/gruf/go-pools v1.1.0/go.mod h1:ZMYpt/DjQWYC3zFD3T97QWSFKs62zAUGJ/tzvgB9D68=
|
||||||
codeberg.org/gruf/go-runners v1.1.1/go.mod h1:9gTrmMnO3d+50C+hVzcmGBf+zTuswReS278E2EMvnmw=
|
codeberg.org/gruf/go-runners v1.1.1/go.mod h1:9gTrmMnO3d+50C+hVzcmGBf+zTuswReS278E2EMvnmw=
|
||||||
codeberg.org/gruf/go-runners v1.2.1 h1:eXXofOMkLTkrdqI0qFYm00hP9IW42JZbc+IRKgVyQ28=
|
|
||||||
codeberg.org/gruf/go-runners v1.2.1/go.mod h1:9gTrmMnO3d+50C+hVzcmGBf+zTuswReS278E2EMvnmw=
|
codeberg.org/gruf/go-runners v1.2.1/go.mod h1:9gTrmMnO3d+50C+hVzcmGBf+zTuswReS278E2EMvnmw=
|
||||||
codeberg.org/gruf/go-sched v1.0.1 h1:+EAXSVI4orY5lMNX2Vrke/UxF2qjmEy6gHcyySZg/3k=
|
codeberg.org/gruf/go-runners v1.2.2 h1:o0u8ggAeT5j8R0oaND961OeWEZOzW9wqwhmnVEeteqs=
|
||||||
codeberg.org/gruf/go-sched v1.0.1/go.mod h1:LFzosJL0yrCNtXg9Vq9iwr4q6ANuRirO2cVwKYH7CLs=
|
codeberg.org/gruf/go-runners v1.2.2/go.mod h1:rl0EdZNozkRMb21DAtOL5L4oTfmslYQdZgq2RMMc/H4=
|
||||||
|
codeberg.org/gruf/go-sched v1.0.4 h1:gEfbDQbPUhCE+JPTo28l3eTaNilP+YXMjXS2e3KOtDQ=
|
||||||
|
codeberg.org/gruf/go-sched v1.0.4/go.mod h1:5C2IQtzxSPR0Q5+EWTAY5HcxZIIFr5B6MtFwL9FtsoA=
|
||||||
codeberg.org/gruf/go-store v1.3.8 h1:7Hzzsa8gaOc6spuGWXJVUWRAyKiOR/m60/jNYrD8cT0=
|
codeberg.org/gruf/go-store v1.3.8 h1:7Hzzsa8gaOc6spuGWXJVUWRAyKiOR/m60/jNYrD8cT0=
|
||||||
codeberg.org/gruf/go-store v1.3.8/go.mod h1:Fy5pXEHiIVFRWDx8DfILwXS1ulrj/jLdSK2C2oElz3I=
|
codeberg.org/gruf/go-store v1.3.8/go.mod h1:Fy5pXEHiIVFRWDx8DfILwXS1ulrj/jLdSK2C2oElz3I=
|
||||||
codeberg.org/gruf/go-ulid v1.0.0/go.mod h1:dVNsZJpVTge8+jfBTjAMpnscYSiCqk+g32ZgtorCAMs=
|
codeberg.org/gruf/go-ulid v1.0.0/go.mod h1:dVNsZJpVTge8+jfBTjAMpnscYSiCqk+g32ZgtorCAMs=
|
||||||
|
|
|
@ -4,8 +4,9 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"codeberg.org/gruf/go-atomics"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FuncRunner provides a means of managing long-running functions e.g. main logic loops.
|
// FuncRunner provides a means of managing long-running functions e.g. main logic loops.
|
||||||
|
@ -17,9 +18,8 @@ type FuncRunner struct {
|
||||||
// provided function. This can be used both for logging, and for error filtering
|
// provided function. This can be used both for logging, and for error filtering
|
||||||
ErrorHandler func(err error) error
|
ErrorHandler func(err error) error
|
||||||
|
|
||||||
svc Service // underlying service to manage start/stop
|
svc Service // underlying service to manage start/stop
|
||||||
err error // last-set error
|
err atomics.Error
|
||||||
mu sync.Mutex // protects err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go will attempt to run 'fn' asynchronously. The provided context is used to propagate requested
|
// Go will attempt to run 'fn' asynchronously. The provided context is used to propagate requested
|
||||||
|
@ -28,22 +28,20 @@ type FuncRunner struct {
|
||||||
// time before considering the function as handed off. Returned bool is success state, i.e. returns true
|
// time before considering the function as handed off. Returned bool is success state, i.e. returns true
|
||||||
// if function is successfully handed off or returns within hand off time with nil error.
|
// if function is successfully handed off or returns within hand off time with nil error.
|
||||||
func (r *FuncRunner) Go(fn func(ctx context.Context) error) bool {
|
func (r *FuncRunner) Go(fn func(ctx context.Context) error) bool {
|
||||||
|
var has bool
|
||||||
|
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
var cancelled bool
|
var cancelled bool
|
||||||
|
|
||||||
has := r.svc.Run(func(ctx context.Context) {
|
has = r.svc.Run(func(ctx context.Context) {
|
||||||
// reset error
|
// reset error
|
||||||
r.mu.Lock()
|
r.err.Store(nil)
|
||||||
r.err = nil
|
|
||||||
r.mu.Unlock()
|
|
||||||
|
|
||||||
// Run supplied func and set errror if returned
|
// Run supplied func and set errror if returned
|
||||||
if err := Run(func() error { return fn(ctx) }); err != nil {
|
if err := Run(func() error { return fn(ctx) }); err != nil {
|
||||||
r.mu.Lock()
|
r.err.Store(err)
|
||||||
r.err = err
|
|
||||||
r.mu.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// signal done
|
// signal done
|
||||||
|
@ -61,19 +59,18 @@ func (r *FuncRunner) Go(fn func(ctx context.Context) error) bool {
|
||||||
switch has {
|
switch has {
|
||||||
// returned after starting
|
// returned after starting
|
||||||
case true:
|
case true:
|
||||||
r.mu.Lock()
|
// Load set error
|
||||||
|
err := r.err.Load()
|
||||||
|
|
||||||
// filter out errors due FuncRunner.Stop() being called
|
// filter out errors due FuncRunner.Stop() being called
|
||||||
if cancelled && errors.Is(r.err, context.Canceled) {
|
if cancelled && errors.Is(err, context.Canceled) {
|
||||||
// filter out errors from FuncRunner.Stop() being called
|
// filter out errors from FuncRunner.Stop() being called
|
||||||
r.err = nil
|
r.err.Store(nil)
|
||||||
} else if r.err != nil && r.ErrorHandler != nil {
|
} else if err != nil && r.ErrorHandler != nil {
|
||||||
// pass any non-nil error to set handler
|
// pass any non-nil error to set handler
|
||||||
r.err = r.ErrorHandler(r.err)
|
r.err.Store(r.ErrorHandler(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
r.mu.Unlock()
|
|
||||||
|
|
||||||
// already running
|
// already running
|
||||||
case false:
|
case false:
|
||||||
close(done)
|
close(done)
|
||||||
|
@ -93,7 +90,7 @@ func (r *FuncRunner) Go(fn func(ctx context.Context) error) bool {
|
||||||
|
|
||||||
// 'fn' returned, check error
|
// 'fn' returned, check error
|
||||||
case <-done:
|
case <-done:
|
||||||
return (r.Err() == nil)
|
return has
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,10 +101,7 @@ func (r *FuncRunner) Stop() bool {
|
||||||
|
|
||||||
// Err returns the last-set error value.
|
// Err returns the last-set error value.
|
||||||
func (r *FuncRunner) Err() error {
|
func (r *FuncRunner) Err() error {
|
||||||
r.mu.Lock()
|
return r.err.Load()
|
||||||
err := r.err
|
|
||||||
r.mu.Unlock()
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run will execute the supplied 'fn' catching any panics. Returns either function-returned error or formatted panic.
|
// Run will execute the supplied 'fn' catching any panics. Returns either function-returned error or formatted panic.
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package sched
|
package sched
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"codeberg.org/gruf/go-atomics"
|
"codeberg.org/gruf/go-atomics"
|
||||||
|
@ -97,3 +100,19 @@ func (job *Job) Run(now time.Time) {
|
||||||
}()
|
}()
|
||||||
job.call(now)
|
job.call(now)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String provides a debuggable string representation of Job including ID, next time and Timing type.
|
||||||
|
func (job *Job) String() string {
|
||||||
|
var buf strings.Builder
|
||||||
|
buf.WriteByte('{')
|
||||||
|
buf.WriteString("id=")
|
||||||
|
buf.WriteString(strconv.FormatUint(job.id, 10))
|
||||||
|
buf.WriteByte(' ')
|
||||||
|
buf.WriteString("next=")
|
||||||
|
buf.WriteString(job.next.Load().Format(time.StampMicro))
|
||||||
|
buf.WriteByte(' ')
|
||||||
|
buf.WriteString("timing=")
|
||||||
|
buf.WriteString(reflect.TypeOf(job.timing).String())
|
||||||
|
buf.WriteByte('}')
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
|
@ -132,7 +132,13 @@ func (sch *Scheduler) run(ctx context.Context) {
|
||||||
// Get next job time
|
// Get next job time
|
||||||
next := sch.jobs[0].Next()
|
next := sch.jobs[0].Next()
|
||||||
|
|
||||||
if until := next.Sub(now); until <= 0 {
|
// If this job is _just_ about to be ready, we
|
||||||
|
// don't bother sleeping. It's wasted cycles only
|
||||||
|
// sleeping for some obscenely tiny amount of time
|
||||||
|
// we can't guarantee precision for.
|
||||||
|
const precision = time.Millisecond
|
||||||
|
|
||||||
|
if until := next.Sub(now); until <= precision/1e3 {
|
||||||
// This job is behind schedule,
|
// This job is behind schedule,
|
||||||
// set timer to always tick
|
// set timer to always tick
|
||||||
tch = alwaysticks
|
tch = alwaysticks
|
||||||
|
@ -155,6 +161,10 @@ func (sch *Scheduler) run(ctx context.Context) {
|
||||||
|
|
||||||
// Timer ticked, run scheduled
|
// Timer ticked, run scheduled
|
||||||
case now := <-tch:
|
case now := <-tch:
|
||||||
|
if !timerset {
|
||||||
|
// alwaysticks returns zero times
|
||||||
|
now = time.Now()
|
||||||
|
}
|
||||||
sch.schedule(now)
|
sch.schedule(now)
|
||||||
|
|
||||||
// Received update, handle job/id
|
// Received update, handle job/id
|
||||||
|
@ -213,7 +223,7 @@ func (sch *Scheduler) schedule(now time.Time) {
|
||||||
// Run this job async!
|
// Run this job async!
|
||||||
go job.Run(now)
|
go job.Run(now)
|
||||||
|
|
||||||
if job.Next().IsZero() {
|
if next.IsZero() {
|
||||||
// Zero time, this job is done and can be dropped
|
// Zero time, this job is done and can be dropped
|
||||||
sch.jobs = append(sch.jobs[:i], sch.jobs[i+1:]...)
|
sch.jobs = append(sch.jobs[:i], sch.jobs[i+1:]...)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -13,7 +13,7 @@ codeberg.org/gruf/go-bytesize
|
||||||
# codeberg.org/gruf/go-byteutil v1.0.2
|
# codeberg.org/gruf/go-byteutil v1.0.2
|
||||||
## explicit; go 1.16
|
## explicit; go 1.16
|
||||||
codeberg.org/gruf/go-byteutil
|
codeberg.org/gruf/go-byteutil
|
||||||
# codeberg.org/gruf/go-cache/v2 v2.1.1
|
# codeberg.org/gruf/go-cache/v2 v2.1.2
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
codeberg.org/gruf/go-cache/v2
|
codeberg.org/gruf/go-cache/v2
|
||||||
# codeberg.org/gruf/go-debug v1.2.0
|
# codeberg.org/gruf/go-debug v1.2.0
|
||||||
|
@ -44,11 +44,11 @@ codeberg.org/gruf/go-mutexes
|
||||||
# codeberg.org/gruf/go-pools v1.1.0
|
# codeberg.org/gruf/go-pools v1.1.0
|
||||||
## explicit; go 1.16
|
## explicit; go 1.16
|
||||||
codeberg.org/gruf/go-pools
|
codeberg.org/gruf/go-pools
|
||||||
# codeberg.org/gruf/go-runners v1.2.1
|
# codeberg.org/gruf/go-runners v1.2.2
|
||||||
## explicit; go 1.14
|
## explicit; go 1.14
|
||||||
codeberg.org/gruf/go-runners
|
codeberg.org/gruf/go-runners
|
||||||
# codeberg.org/gruf/go-sched v1.0.1
|
# codeberg.org/gruf/go-sched v1.0.4
|
||||||
## explicit; go 1.18
|
## explicit; go 1.16
|
||||||
codeberg.org/gruf/go-sched
|
codeberg.org/gruf/go-sched
|
||||||
# codeberg.org/gruf/go-store v1.3.8
|
# codeberg.org/gruf/go-store v1.3.8
|
||||||
## explicit; go 1.14
|
## explicit; go 1.14
|
||||||
|
|
Loading…
Reference in New Issue