-
Notifications
You must be signed in to change notification settings - Fork 80
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #161 from MbolotSuse/resource-schema-improved-cache
Resource schema improved cache
- Loading branch information
Showing
10 changed files
with
751 additions
and
302 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package debounce | ||
|
||
import ( | ||
"context" | ||
"sync" | ||
"time" | ||
|
||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
// Refreshable represents an object which can be refreshed. This should be protected by a mutex for concurrent operation. | ||
type Refreshable interface { | ||
Refresh() error | ||
} | ||
|
||
// DebounceableRefresher is used to debounce multiple attempts to refresh a refreshable type. | ||
type DebounceableRefresher struct { | ||
sync.Mutex | ||
// Refreshable is any type that can be refreshed. The refresh method should by protected by a mutex internally. | ||
Refreshable Refreshable | ||
current context.CancelFunc | ||
} | ||
|
||
// RefreshAfter requests a refresh after a certain time has passed. Subsequent calls to this method will | ||
// delay the requested refresh by the new duration. Note that this is a total override of the previous calls - calling | ||
// RefreshAfter(time.Second * 2) and then immediately calling RefreshAfter(time.Microsecond * 1) will run a refresh | ||
// in one microsecond | ||
func (d *DebounceableRefresher) RefreshAfter(duration time.Duration) { | ||
d.Lock() | ||
defer d.Unlock() | ||
ctx := context.Background() | ||
ctx, cancel := context.WithCancel(ctx) | ||
if d.current != nil { | ||
d.current() | ||
} | ||
d.current = cancel | ||
go func() { | ||
timer := time.NewTimer(duration) | ||
defer timer.Stop() | ||
select { | ||
case <-ctx.Done(): | ||
// this indicates that the context was cancelled. Do nothing. | ||
case <-timer.C: | ||
// note this can cause multiple refreshes to happen concurrently | ||
err := d.Refreshable.Refresh() | ||
if err != nil { | ||
logrus.Errorf("failed to refresh with error: %v", err) | ||
} | ||
} | ||
}() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package debounce | ||
|
||
import ( | ||
"fmt" | ||
"sync/atomic" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
type refreshable struct { | ||
wasRefreshed atomic.Bool | ||
retErr error | ||
} | ||
|
||
func (r *refreshable) Refresh() error { | ||
r.wasRefreshed.Store(true) | ||
return r.retErr | ||
} | ||
|
||
func TestRefreshAfter(t *testing.T) { | ||
ref := refreshable{} | ||
debounce := DebounceableRefresher{ | ||
Refreshable: &ref, | ||
} | ||
debounce.RefreshAfter(time.Millisecond * 2) | ||
debounce.RefreshAfter(time.Microsecond * 2) | ||
time.Sleep(time.Millisecond * 1) | ||
// test that the second refresh call overrode the first - Micro < Milli so this should have ran | ||
require.True(t, ref.wasRefreshed.Load()) | ||
ref.wasRefreshed.Store(false) | ||
time.Sleep(time.Millisecond * 2) | ||
// test that the call was debounced - though we called this twice only one refresh should be called | ||
require.False(t, ref.wasRefreshed.Load()) | ||
|
||
ref = refreshable{ | ||
retErr: fmt.Errorf("Some error"), | ||
} | ||
debounce = DebounceableRefresher{ | ||
Refreshable: &ref, | ||
} | ||
debounce.RefreshAfter(time.Microsecond * 2) | ||
// test the error case | ||
time.Sleep(time.Millisecond * 1) | ||
require.True(t, ref.wasRefreshed.Load()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.