7
7
package nightwatch
8
8
9
9
import (
10
- "context"
11
- "errors"
12
- "time"
13
-
14
- "github.com/go-redsync/redsync/v4"
15
- "github.com/go-redsync/redsync/v4/redis/goredis/v9"
16
10
"github.com/jinzhu/copier"
17
- "github.com/robfig/cron/v3"
18
11
"k8s.io/apimachinery/pkg/util/wait"
19
12
20
13
"github.com/superproj/onex/internal/nightwatch/watcher"
21
14
"github.com/superproj/onex/pkg/db"
22
15
clientset "github.com/superproj/onex/pkg/generated/clientset/versioned"
23
16
"github.com/superproj/onex/pkg/log"
17
+ "github.com/superproj/onex/pkg/watch"
18
+ onexlogger "github.com/superproj/onex/pkg/watch/logger/onex"
24
19
25
20
// trigger init functions in `internal/nightwatch/watcher/all`.
26
21
_ "github.com/superproj/onex/internal/nightwatch/watcher/all"
27
22
genericoptions "github.com/superproj/onex/pkg/options"
28
- stringsutil "github.com/superproj/onex/pkg/util/strings"
29
- )
30
-
31
- var (
32
- lockName = "onex-nightwatch-lock2"
33
- jobStopTimeout = 3 * time .Minute
34
- extendExpiration = 5 * time .Second
35
- defaultExpiration = 10 * extendExpiration
36
23
)
37
24
38
25
type nightWatch struct {
39
- runner * cron.Cron
40
- // distributed lock
41
- locker * redsync.Mutex
42
- config * watcher.Config
43
- disableWatchers []string
26
+ * watch.Watch
44
27
}
45
28
46
29
// Config is the configuration for the nightwatch server.
47
30
type Config struct {
48
31
MySQLOptions * genericoptions.MySQLOptions
49
32
RedisOptions * genericoptions.RedisOptions
33
+ WatchOptions * watch.Options
50
34
// The maximum concurrency event of user watcher.
51
35
UserWatcherMaxWorkers int64
52
36
// The list of watchers that should be disabled.
53
- DisableWatchers []string
54
- Client clientset.Interface
37
+ Client clientset.Interface
55
38
}
56
39
57
40
// CompletedConfig same as Config, just to swap private object.
@@ -65,7 +48,7 @@ func (c *Config) Complete() *CompletedConfig {
65
48
}
66
49
67
50
// CreateWatcherConfig used to create configuration used by all watcher.
68
- func (c * Config ) CreateWatcherConfig () (* watcher.Config , error ) {
51
+ func (c * Config ) CreateWatcherConfig () (* watcher.AggregateConfig , error ) {
69
52
var mysqlOptions db.MySQLOptions
70
53
_ = copier .Copy (& mysqlOptions , c .MySQLOptions )
71
54
storeClient , err := wireStoreClient (& mysqlOptions )
@@ -74,7 +57,7 @@ func (c *Config) CreateWatcherConfig() (*watcher.Config, error) {
74
57
return nil , err
75
58
}
76
59
77
- return & watcher.Config {
60
+ return & watcher.AggregateConfig {
78
61
Store : storeClient ,
79
62
Client : c .Client ,
80
63
UserWatcherMaxWorkers : c .UserWatcherMaxWorkers ,
@@ -83,118 +66,36 @@ func (c *Config) CreateWatcherConfig() (*watcher.Config, error) {
83
66
84
67
// New creates an asynchronous task instance.
85
68
func (c * Config ) New () (* nightWatch , error ) {
86
- // Create a pool with go-redis which is the pool redisync will
87
- // use while communicating with Redis. This can also be any pool that
88
- // implements the `redis.Pool` interface.
89
69
client , err := c .RedisOptions .NewClient ()
90
70
if err != nil {
91
71
log .Errorw (err , "Failed to create Redis client" )
92
72
return nil , err
93
73
}
94
74
95
- logger := newCronLogger ()
96
- runner := cron .New (
97
- cron .WithSeconds (),
98
- cron .WithLogger (logger ),
99
- cron .WithChain (cron .SkipIfStillRunning (logger ), cron .Recover (logger )),
100
- )
101
-
102
- pool := goredis .NewPool (client )
103
- lockOpts := []redsync.Option {
104
- redsync .WithRetryDelay (50 * time .Microsecond ),
105
- redsync .WithTries (3 ),
106
- redsync .WithExpiry (defaultExpiration ),
107
- }
108
- // Create an instance of redisync and obtain a new mutex by using the same name
109
- // for all instances wanting the same lock.
110
- locker := redsync .New (pool ).NewMutex (lockName , lockOpts ... )
111
-
112
75
cfg , err := c .CreateWatcherConfig ()
113
76
if err != nil {
114
77
return nil , err
115
78
}
116
79
117
- nw := & nightWatch {runner : runner , locker : locker , config : cfg , disableWatchers : c .DisableWatchers }
118
- if err := nw .addWatchers (); err != nil {
119
- return nil , err
80
+ initialize := watcher .NewWatcherInitializer (cfg .Store , cfg .Client , cfg .UserWatcherMaxWorkers )
81
+ opts := []watch.Option {
82
+ watch .WithInitialize (initialize ),
83
+ watch .WithLogger (onexlogger .NewLogger ()),
84
+ watch .WithLockName ("onex-nightwatch-lock" ),
120
85
}
121
86
122
- return nw , nil
123
- }
124
-
125
- // addWatchers used to initialize all registered watchers and add the watchers as a Cron job.
126
- func (nw * nightWatch ) addWatchers () error {
127
- for n , w := range watcher .ListWatchers () {
128
- if stringsutil .StringIn (n , nw .disableWatchers ) {
129
- continue
130
- }
131
-
132
- if err := w .Initialize (context .Background (), nw .config ); err != nil {
133
- log .Errorw (err , "Failed to construct watcher" , "watcher" , n )
134
- return err
135
- }
136
-
137
- spec := watcher .Every3Seconds
138
- if obj , ok := w .(watcher.ISpec ); ok {
139
- spec = obj .Spec ()
140
- }
141
-
142
- if _ , err := nw .runner .AddJob (spec , w ); err != nil {
143
- log .Errorw (err , "Failed to add job to the cron" , "watcher" , n )
144
- return err
145
- }
87
+ nw , err := watch .NewWatch (c .WatchOptions , client , opts ... )
88
+ if err != nil {
89
+ return nil , err
146
90
}
147
91
148
- return nil
92
+ return & nightWatch { nw }, nil
149
93
}
150
94
151
95
// Run keep retrying to acquire lock and then start the Cron job.
152
96
func (nw * nightWatch ) Run (stopCh <- chan struct {}) {
153
- ctx := wait .ContextForChannel (stopCh )
154
-
155
- ticker := time .NewTicker (defaultExpiration + (5 * time .Second ))
156
- for {
157
- // Obtain a lock for our given mutex. After this is successful, no one else
158
- // can obtain the same lock (the same mutex name) until we unlock it.
159
- err := nw .locker .LockContext (ctx )
160
- if err == nil {
161
- log .Debugw ("Successfully acquired lock" , "lockName" , lockName )
162
- break
163
- }
164
- log .Debugw ("Failed to acquire lock." , "lockName" , lockName , "err" , err )
165
- <- ticker .C
166
- }
167
-
168
- go func () {
169
- ticker := time .NewTicker (extendExpiration )
170
- for {
171
- <- ticker .C
172
- if ok , err := nw .locker .ExtendContext (ctx ); ! ok || err != nil {
173
- log .Debugw ("Failed to extend mutex" , "err" , err , "status" , ok )
174
- }
175
- }
176
- }()
177
-
178
- nw .runner .Start ()
179
- log .Infof ("Successfully started nightwatch server" )
180
-
97
+ nw .Start (wait .ContextForChannel (stopCh ))
98
+ // graceful shutdown
181
99
<- stopCh
182
-
183
- nw .stop ()
184
- }
185
-
186
- // stop used to blocking waits for the job to complete and releases the lock.
187
- func (nw * nightWatch ) stop () {
188
- ctx := nw .runner .Stop ()
189
- select {
190
- case <- ctx .Done ():
191
- case <- time .After (jobStopTimeout ):
192
- log .Errorw (errors .New ("context was not done immediately" ), "timeout" , jobStopTimeout .String ())
193
- }
194
-
195
- if ok , err := nw .locker .Unlock (); ! ok || err != nil {
196
- log .Debugw ("Failed to unlock" , "err" , err , "status" , ok )
197
- }
198
-
199
- log .Infof ("Successfully stopped nightwatch server" )
100
+ nw .Stop ()
200
101
}
0 commit comments