Skip to content

Commit 6711adb

Browse files
authored
Merge pull request #31 from donutloop/feat/lease
Leaser: Lease the resource for duration. When the lease expires, invo…
2 parents 1b892e2 + ec96059 commit 6711adb

File tree

5 files changed

+142
-2
lines changed

5 files changed

+142
-2
lines changed

debugutil/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Usage
22

3-
PrettyPrint generates a human readable representation of the value v.
3+
PrettySprint generates a human readable representation of the value v.
44

55
## Example
66
```go
@@ -12,6 +12,6 @@ import (
1212
)
1313

1414
func main() {
15-
debugutil.PrettyPrint([]string{})
15+
log.Println(debugutil.PrettySprint([]string{})
1616
}
1717
```

lease/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Usage
2+
3+
lease the resource for duration. When the lease expires, invoke func
4+
5+
## Example
6+
```go
7+
package main
8+
9+
import (
10+
"github.com/donutloop/toolkit/lease"
11+
)
12+
13+
func main() {
14+
leaser := lease.NewLeaser()
15+
leaser.Lease("cleanup-cache", time.Duration(1*time.Second), func() {
16+
fmt.Println("cleaned up cache")
17+
})
18+
}
19+
```

lease/doc_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package lease_test
2+
3+
import (
4+
"fmt"
5+
"time"
6+
7+
"github.com/donutloop/toolkit/lease"
8+
)
9+
10+
func ExampleLeaser_Lease() {
11+
12+
leaser := lease.NewLeaser()
13+
leaser.Lease("cleanup-cache", time.Duration(1*time.Second), func() {
14+
fmt.Println("cleaned up cache")
15+
})
16+
17+
<-time.After(2 * time.Second)
18+
19+
// Output: cleaned up cache
20+
}

lease/lease.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package lease
2+
3+
import "time"
4+
5+
type Leaser interface {
6+
// lease the resource r for duration. When the lease expires, invoke func call.
7+
// revoke a lease can be refreshed by calling Lease() again on the same resource
8+
Lease(r string, d time.Duration, revoke func())
9+
// if resource exists then cancel the old timer and delete the entry
10+
Return(r string) bool
11+
}
12+
13+
// NewLeaser creates a instance of leaser
14+
func NewLeaser() Leaser {
15+
return &leaser{
16+
timers: make(map[string]*time.Timer),
17+
}
18+
}
19+
20+
type leaser struct {
21+
timers map[string]*time.Timer
22+
}
23+
24+
func (l *leaser) Lease(r string, d time.Duration, f func()) {
25+
timer := time.AfterFunc(d, f)
26+
// if resource exists then cancel the old timer and overwrite the old one
27+
if t, ok := l.timers[r]; ok {
28+
t.Stop()
29+
}
30+
l.timers[r] = timer
31+
}
32+
33+
// if resource exists then cancel the old timer and delete the entry
34+
func (l *leaser) Return(r string) bool {
35+
if t, ok := l.timers[r]; ok {
36+
t.Stop()
37+
return true
38+
}
39+
return false
40+
}

lease/lease_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package lease_test
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"sync/atomic"
8+
9+
"github.com/donutloop/toolkit/lease"
10+
)
11+
12+
func TestLeaser_Lease(t *testing.T) {
13+
var counter int32
14+
leaser := lease.NewLeaser()
15+
leaser.Lease("cleanup-cache", time.Duration(1*time.Second), func() {
16+
atomic.AddInt32(&counter, 1)
17+
})
18+
19+
<-time.After(2 * time.Second)
20+
21+
if counter != 1 {
22+
t.Errorf(`unexpected counter value (actual:"%d", expected: "%d")`, counter, 1)
23+
}
24+
}
25+
26+
func TestLeaser_OverwriteLease(t *testing.T) {
27+
var counter int32
28+
leaser := lease.NewLeaser()
29+
leaser.Lease("cleanup-cache", time.Duration(2*time.Second), func() {
30+
atomic.AddInt32(&counter, 1)
31+
})
32+
33+
leaser.Lease("cleanup-cache", time.Duration(1*time.Second), func() {
34+
atomic.AddInt32(&counter, 2)
35+
})
36+
37+
<-time.After(3 * time.Second)
38+
39+
if counter != 2 {
40+
t.Errorf(`unexpected counter value (actual:"%d", expected: "%d")`, counter, 2)
41+
}
42+
}
43+
44+
func TestLeaser_Return(t *testing.T) {
45+
var counter int32
46+
leaser := lease.NewLeaser()
47+
leaser.Lease("cleanup-cache", time.Duration(1*time.Second), func() {
48+
atomic.AddInt32(&counter, 1)
49+
})
50+
51+
ok := leaser.Return("cleanup-cache")
52+
if !ok {
53+
t.Error("error couldn't return resource")
54+
}
55+
56+
<-time.After(2 * time.Second)
57+
58+
if counter != 0 {
59+
t.Errorf(`unexpected counter value (actual:"%d", expected: "%d")`, counter, 0)
60+
}
61+
}

0 commit comments

Comments
 (0)