diff --git a/lib/oauthutil/renew.go b/lib/oauthutil/renew.go index 7f98491e8..e3652ee9c 100644 --- a/lib/oauthutil/renew.go +++ b/lib/oauthutil/renew.go @@ -1,6 +1,7 @@ package oauthutil import ( + "sync" "sync/atomic" "github.com/rclone/rclone/fs" @@ -8,10 +9,12 @@ import ( // Renew allows tokens to be renewed on expiry if uploads are in progress. type Renew struct { - name string // name to use in logs - ts *TokenSource // token source that needs renewing - uploads atomic.Int32 // number of uploads in progress - run func() error // a transaction to run to renew the token on + name string // name to use in logs + ts *TokenSource // token source that needs renewing + uploads atomic.Int32 // number of uploads in progress + run func() error // a transaction to run to renew the token on + done chan any // channel to end the go routine + shutdown sync.Once } // NewRenew creates a new Renew struct and starts a background process @@ -24,6 +27,7 @@ func NewRenew(name string, ts *TokenSource, run func() error) *Renew { name: name, ts: ts, run: run, + done: make(chan any), } go r.renewOnExpiry() return r @@ -36,7 +40,11 @@ func NewRenew(name string, ts *TokenSource, run func() error) *Renew { func (r *Renew) renewOnExpiry() { expiry := r.ts.OnExpiry() for { - <-expiry + select { + case <-expiry: + case <-r.done: + return + } uploads := r.uploads.Load() if uploads != 0 { fs.Debugf(r.name, "Token expired - %d uploads in progress - refreshing", uploads) @@ -72,3 +80,15 @@ func (r *Renew) Invalidate() { func (r *Renew) Expire() error { return r.ts.Expire() } + +// Shutdown stops the timer and no more renewal will take place. +func (r *Renew) Shutdown() { + if r == nil { + return + } + // closing a channel can only be done once + r.shutdown.Do(func() { + r.ts.expiryTimer.Stop() + close(r.done) + }) +}