status-go/server/timeout.go
frank 38308d48f2
feat_: log on panic (#5849)
* feat_: log error and stacktrace when panic in goroutine

* test_: add test TestSafeGo

* chore_: rename logAndCall to call

* chore_: rename SafeGo to Go

* chore_: make lint-fix

* chore_: use t.Cleanup

* chore_: Revert "chore_: use t.Cleanup"

This reverts commit 4eb420d179cc0e208e84c13cb941e6b3d1ed9819.

* chore_: Revert "chore_: make lint-fix"

This reverts commit fcc995f157e671a4229b47419c3a0e4004b5fdab.

* chore_: Revert "chore_: rename SafeGo to Go"

This reverts commit a6d73d6df583f313032d79aac62f66328039cb55.

* chore_: Revert "chore_: rename logAndCall to call"

This reverts commit 8fbe993bedb9fbba67349a44f151e2dd5e3bc4cc.

* chore_: Revert "test_: add test TestSafeGo"

This reverts commit a1fa91839f3960398980c6bf456e6462ec944819.

* chore_: Revert "feat_: log error and stacktrace when panic in goroutine"

This reverts commit f612dd828fa2ce410d0e806fe773ecbe3e86a68a.

* feat_: log error and stacktrace when panic in goroutine

* chore_: make lint-fix

* chore_: rename logAndCall to call

* chore_: renaming LogOnPanic

* chore_: update rest goroutine function calls

* chore_: make lint-fix
2024-09-27 06:37:32 +08:00

98 lines
2.5 KiB
Go

package server
import (
"sync"
"time"
"github.com/status-im/status-go/common"
)
// timeoutManager represents a discrete encapsulation of timeout functionality.
// this struct expose 3 functions:
// - SetTimeout
// - StartTimeout
// - StopTimeout
type timeoutManager struct {
// timeout number of milliseconds the timeout operation will run before executing the `terminate` func()
// 0 represents an inactive timeout
timeout uint
// exitQueue handles the cancel signal channels that circumvent timeout operations and prevent the
// execution of any `terminate` func()
exitQueue *exitQueueManager
}
// newTimeoutManager returns a fully qualified and initialised timeoutManager
func newTimeoutManager() *timeoutManager {
return &timeoutManager{
exitQueue: &exitQueueManager{queue: []chan struct{}{}},
}
}
// SetTimeout sets the value of the timeoutManager.timeout
func (t *timeoutManager) SetTimeout(milliseconds uint) {
t.timeout = milliseconds
}
// StartTimeout starts a timeout operation based on the set timeoutManager.timeout value
// the given terminate func() will be executed once the timeout duration has passed
func (t *timeoutManager) StartTimeout(terminate func()) {
if t.timeout == 0 {
return
}
t.StopTimeout()
exit := make(chan struct{}, 1)
t.exitQueue.add(exit)
go t.run(terminate, exit)
}
// StopTimeout terminates a timeout operation and exits gracefully
func (t *timeoutManager) StopTimeout() {
if t.timeout == 0 {
return
}
t.exitQueue.empty()
}
// run inits the main timeout run function that awaits for the exit command to be triggered or for the
// timeout duration to elapse and trigger the parameter terminate function.
func (t *timeoutManager) run(terminate func(), exit chan struct{}) {
defer common.LogOnPanic()
select {
case <-exit:
return
case <-time.After(time.Duration(t.timeout) * time.Millisecond):
terminate()
// TODO fire signal to let UI know
// https://github.com/status-im/status-go/issues/3305
return
}
}
// exitQueueManager
type exitQueueManager struct {
queue []chan struct{}
queueLock sync.Mutex
}
// add handles new exit channels adding them to the exit queue
func (e *exitQueueManager) add(exit chan struct{}) {
e.queueLock.Lock()
defer e.queueLock.Unlock()
e.queue = append(e.queue, exit)
}
// empty sends a signal to every exit channel in the queue and then resets the queue
func (e *exitQueueManager) empty() {
e.queueLock.Lock()
defer e.queueLock.Unlock()
for i := range e.queue {
e.queue[i] <- struct{}{}
}
e.queue = []chan struct{}{}
}