Skip to content

Commit 7846c5d

Browse files
committed
Add TickWatch.
Add Log4thLongRoute dev setting. Reduce boilerplate.
1 parent d91897e commit 7846c5d

File tree

4 files changed

+159
-27
lines changed

4 files changed

+159
-27
lines changed

common/site.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ type devConfig struct {
160160
//ExpFix1 bool // unlisted setting, experimental fix for http/1.1 conn hangs
161161
LogLongTick bool // unlisted setting
162162
LogNewLongRoute bool // unlisted setting
163+
Log4thLongRoute bool // unlisted setting
163164
}
164165

165166
// configHolder is purely for having a big struct to unmarshal data into

common/tickloop.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package common
22

33
import (
4+
"fmt"
45
"log"
56
"strconv"
7+
"strings"
68
"sync/atomic"
79
"time"
810

911
qgen "github.com/Azareal/Gosora/query_gen"
12+
"github.com/Azareal/Gosora/uutils"
1013
"github.com/pkg/errors"
1114
)
1215

@@ -215,3 +218,97 @@ func Dailies() (e error) {
215218

216219
return nil
217220
}
221+
222+
type TickWatch struct {
223+
Name string
224+
Start int64
225+
DBCheck int64
226+
StartHook int64
227+
Tasks int64
228+
EndHook int64
229+
230+
Ticker *time.Ticker
231+
Deadline *time.Ticker
232+
EndChan chan bool
233+
}
234+
235+
func NewTickWatch() *TickWatch {
236+
return &TickWatch{
237+
Ticker: time.NewTicker(time.Second * 5),
238+
Deadline: time.NewTicker(time.Hour),
239+
}
240+
}
241+
242+
func (w *TickWatch) DumpElapsed() {
243+
var sb strings.Builder
244+
f := func(str string) {
245+
sb.WriteString(str)
246+
}
247+
ff := func(str string, args ...interface{}) {
248+
f(fmt.Sprintf(str, args...))
249+
}
250+
secs := func(name string, bef, v int64) {
251+
if bef == 0 || v == 0 {
252+
ff("%s: %d\n", v)
253+
}
254+
ff("%s: %d - %.2f secs\n", name, v, time.Duration(bef-v).Seconds())
255+
}
256+
257+
f("Name: " + w.Name + "\n")
258+
ff("Start: %d\n", w.Start)
259+
secs("DBCheck", w.Start, w.DBCheck)
260+
secs("StartHook", w.DBCheck, w.StartHook)
261+
secs("Tasks", w.StartHook, w.Tasks)
262+
secs("EndHook", w.Tasks, w.EndHook)
263+
264+
Log(sb.String())
265+
}
266+
267+
func (w *TickWatch) Run() {
268+
w.EndChan = make(chan bool)
269+
// Use a goroutine to circumvent ticks which never end
270+
go func() {
271+
defer w.Ticker.Stop()
272+
defer close(w.EndChan)
273+
defer EatPanics()
274+
var n int
275+
for {
276+
select {
277+
case <-w.Ticker.C:
278+
Logf("%d seconds elapsed since tick %s started", 5*n, w.Name)
279+
n++
280+
case <-w.Deadline.C:
281+
Log("Hit TickWatch deadline")
282+
dur := time.Duration(uutils.Nanotime() - w.Start)
283+
if dur.Seconds() > 5 {
284+
Log("tick " + w.Name + " has run for " + dur.String())
285+
w.DumpElapsed()
286+
}
287+
return
288+
case <-w.EndChan:
289+
dur := time.Duration(uutils.Nanotime() - w.Start)
290+
if dur.Seconds() > 5 {
291+
Log("tick " + w.Name + " completed in " + dur.String())
292+
w.DumpElapsed()
293+
}
294+
return
295+
}
296+
}
297+
}()
298+
}
299+
300+
func (w *TickWatch) Stop() {
301+
w.EndChan <- true
302+
}
303+
304+
func (w *TickWatch) Set(a *int64, v int64) {
305+
atomic.StoreInt64(a, v)
306+
}
307+
308+
func (w *TickWatch) Clear() {
309+
w.Start = 0
310+
w.DBCheck = 0
311+
w.StartHook = 0
312+
w.Tasks = 0
313+
w.EndHook = 0
314+
}

main.go

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
_ "github.com/Azareal/Gosora/extend"
3434
qgen "github.com/Azareal/Gosora/query_gen"
3535
"github.com/Azareal/Gosora/routes"
36+
"github.com/Azareal/Gosora/uutils"
3637
"github.com/fsnotify/fsnotify"
3738

3839
//"github.com/lucas-clemente/quic-go/http3"
@@ -602,15 +603,32 @@ func main() {
602603
sig := <-sigs
603604
log.Print("Received a signal to shutdown: ", sig)
604605
// TODO: Gracefully shutdown the HTTP server
605-
if e := runHook("before_shutdown_tick"); e != nil {
606-
log.Print("before_shutdown_tick err:", e)
607-
}
608-
log.Print("Running shutdown tasks")
609-
c.Tasks.Shutdown.Run()
610-
log.Print("Ran shutdown tasks")
611-
if e := runHook("after_shutdown_tick"); e != nil {
612-
log.Print("after_shutdown_tick err:", e)
606+
tw, cn := c.NewTickWatch(), uutils.Nanotime()
607+
tw.Name = "shutdown"
608+
tw.Set(&tw.Start, cn)
609+
tw.Set(&tw.DBCheck, cn)
610+
tw.Run()
611+
n, e := func() (string, error) {
612+
if e := runHook("before_shutdown_tick"); e != nil {
613+
return "before_shutdown_tick ", e
614+
}
615+
tw.Set(&tw.StartHook, uutils.Nanotime())
616+
log.Print("Running shutdown tasks")
617+
if e := c.Tasks.Shutdown.Run(); e != nil {
618+
return "shutdown tasks ", e
619+
}
620+
tw.Set(&tw.Tasks, uutils.Nanotime())
621+
log.Print("Ran shutdown tasks")
622+
if e := runHook("after_shutdown_tick"); e != nil {
623+
return "after_shutdown_tick ", e
624+
}
625+
tw.Set(&tw.EndHook, uutils.Nanotime())
626+
return "", nil
627+
}()
628+
if e != nil {
629+
log.Print(n+" err:", e)
613630
}
631+
tw.Stop()
614632
log.Print("Stopping server")
615633
c.StoppedServer("Stopped server")
616634
}()
@@ -650,26 +668,19 @@ func main() {
650668
}
651669

652670
func startServer() {
653-
// We might not need the timeouts, if we're behind a reverse-proxy like Nginx
671+
// We might not need timeouts, if we're behind a reverse-proxy like Nginx
654672
newServer := func(addr string, h http.Handler) *http.Server {
655-
rtime := c.Config.ReadTimeout
656-
if rtime == 0 {
657-
rtime = 8
658-
} else if rtime == -1 {
659-
rtime = 0
660-
}
661-
wtime := c.Config.WriteTimeout
662-
if wtime == 0 {
663-
wtime = 10
664-
} else if wtime == -1 {
665-
wtime = 0
666-
}
667-
itime := c.Config.IdleTimeout
668-
if itime == 0 {
669-
itime = 120
670-
} else if itime == -1 {
671-
itime = 0
673+
f := func(timeout, dval int) int {
674+
if timeout == 0 {
675+
timeout = dval
676+
} else if timeout == -1 {
677+
timeout = 0
678+
}
679+
return timeout
672680
}
681+
rtime := f(c.Config.ReadTimeout, 8)
682+
wtime := f(c.Config.WriteTimeout, 10)
683+
itime := f(c.Config.IdleTimeout, 120)
673684
return &http.Server{
674685
Addr: addr,
675686
Handler: h,

tickloop.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,30 @@ func tickLoop(thumbChan chan bool) error {
6060
}
6161

6262
tick := func(name string, tasks c.TaskSet, secs int) error {
63+
tw := c.NewTickWatch()
64+
tw.Name = name
65+
tw.Set(&tw.Start, uutils.Nanotime())
66+
tw.Run()
67+
defer tw.Stop()
6368
if c.StartTick() {
6469
return nil
6570
}
71+
tw.Set(&tw.DBCheck, uutils.Nanotime())
6672
if e := runHook("before_" + name + "_tick"); e != nil {
6773
return e
6874
}
6975
cn := uutils.Nanotime()
76+
tw.Set(&tw.StartHook, cn)
7077
if e := tasks.Run(); e != nil {
7178
return e
7279
}
80+
tw.Set(&tw.Tasks, uutils.Nanotime())
7381
handleLogLongTick(name, cn, secs)
74-
return runHook("after_" + name + "_tick")
82+
if e := runHook("after_" + name + "_tick"); e != nil {
83+
return e
84+
}
85+
tw.Set(&tw.EndHook, uutils.Nanotime())
86+
return nil
7587
}
7688

7789
tl.HalfSecf = func() error {
@@ -220,6 +232,8 @@ func sched() error {
220232
return nil
221233
}
222234

235+
var pingLastTopicCount = 1
236+
223237
// TODO: Move somewhere else
224238
func PingLastTopicTick() error {
225239
g, e := c.Groups.Get(c.GuestUser.Group)
@@ -258,6 +272,15 @@ func PingLastTopicTick() error {
258272
dur := time.Duration(uutils.Nanotime() - cn)
259273
if dur.Seconds() > 5 {
260274
c.Log("topic " + sid + " completed in " + dur.String())
275+
} else if c.Dev.Log4thLongRoute {
276+
pingLastTopicCount++
277+
if pingLastTopicCount == 4 {
278+
c.Log("topic " + sid + " completed in " + dur.String())
279+
}
280+
if pingLastTopicCount >= 4 {
281+
pingLastTopicCount = 1
282+
}
261283
}
284+
262285
return nil
263286
}

0 commit comments

Comments
 (0)