Skip to content

Commit 812c591

Browse files
committed
Start
1 parent aa90e65 commit 812c591

File tree

5 files changed

+143
-0
lines changed

5 files changed

+143
-0
lines changed

cmd/main.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/ehsaniara/gointerlock"
7+
"log"
8+
"time"
9+
)
10+
11+
func myJob() {
12+
fmt.Println(time.Now(), " - called")
13+
}
14+
15+
func main() {
16+
17+
//test cron
18+
var jobTicker = gointerlock.GoInterval{
19+
Name: "MyTestJob",
20+
Interval: 2 * time.Second,
21+
Arg: myJob,
22+
}
23+
err := jobTicker.Run(context.Background())
24+
if err != nil {
25+
log.Fatalf("Error: %s", err)
26+
}
27+
28+
}

go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module github.com/ehsaniara/gointerlock
2+
3+
go 1.16
4+
5+
require github.com/go-redis/redis/v8 v8.11.1

goInterval.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package gointerlock
2+
3+
import (
4+
"context"
5+
"errors"
6+
"github.com/go-redis/redis/v8"
7+
"log"
8+
"time"
9+
)
10+
11+
type GoInterval struct {
12+
Name string
13+
Arg func()
14+
Interval time.Duration
15+
timer *time.Timer
16+
RedisConnector *redis.Client
17+
}
18+
19+
func (t *GoInterval) Run(ctx context.Context) error {
20+
21+
if ctx == nil {
22+
ctx = context.Background()
23+
}
24+
25+
if t.Interval == 0 {
26+
return errors.New("`Time Interval is missing!`")
27+
}
28+
if t.Arg == nil {
29+
return errors.New("`What this timer should to run?`")
30+
}
31+
32+
var locker Locker
33+
locker.redisConnector = t.RedisConnector
34+
35+
if locker.redisConnector == nil && t.Name == "" {
36+
return errors.New("`Distributed Jobs should have a unique name!`")
37+
}
38+
39+
t.updateTimer()
40+
for {
41+
select {
42+
case <-ctx.Done():
43+
log.Printf("Job %s is terminated", t.Name)
44+
return nil
45+
default:
46+
47+
<-t.timer.C
48+
//lock
49+
locked, errLock := locker.Lock(ctx, t.Name)
50+
if errLock != nil {
51+
return errLock
52+
}
53+
if locked {
54+
// run the task
55+
t.Arg()
56+
//unlock
57+
errUnlock := locker.Unlock(ctx, t.Name)
58+
if errUnlock != nil {
59+
return errUnlock
60+
}
61+
}
62+
t.updateTimer()
63+
}
64+
}
65+
}
66+
67+
func (t *GoInterval) updateTimer() {
68+
nextTick := time.Now()
69+
if !nextTick.After(time.Now()) {
70+
nextTick = nextTick.Add(t.Interval)
71+
}
72+
diff := nextTick.Sub(time.Now())
73+
if t.timer == nil {
74+
t.timer = time.NewTimer(diff)
75+
} else {
76+
t.timer.Reset(diff)
77+
}
78+
}

goIntervalLock.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package gointerlock
2+
3+
import (
4+
"context"
5+
"github.com/go-redis/redis/v8"
6+
"time"
7+
)
8+
9+
type Locker struct {
10+
redisConnector *redis.Client
11+
}
12+
13+
func (s *Locker) Lock(ctx context.Context, key string) (success bool, err error) {
14+
if s.redisConnector != nil {
15+
16+
res, err := s.redisConnector.SetNX(ctx, key, time.Now().String(), time.Second*15).Result()
17+
if err != nil {
18+
return false, err
19+
}
20+
return res, nil
21+
}
22+
return true, nil
23+
}
24+
25+
func (s *Locker) Unlock(ctx context.Context, key string) error {
26+
if s.redisConnector != nil {
27+
return s.redisConnector.Del(ctx, key).Err()
28+
} else {
29+
return nil
30+
}
31+
}

goInterval_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package gointerlock

0 commit comments

Comments
 (0)