Home >Backend Development >Golang >Goroutines called recursively by time.AfterFunc() are poorly designed
php editor Xigua believes that the sentence "The design of goroutine called recursively by time.AfterFunc() is very bad" reflects an unreasonable design idea. In concurrent programming, recursively calling goroutines may cause excessive resource consumption, and even cause problems such as deadlock and memory overflow. Therefore, recursive calls should be used with caution and other alternatives to solve the problem should be considered to ensure the performance and stability of the program. When writing code, we should always pay attention to the rationality of the design to avoid unnecessary problems.
I have a small http application (A). On startup, it calls another http service (B) to verify the license and if the license is OK, the http server (A) starts. If verification fails A, a fatal error occurs and exit
License checks are performed every 24 hours
Would it be considered a bad design to recursively create a new goroutine every 24 hours? Check my code below. Will the previous goroutine be closed or continue to run, and then n goroutines will call each other and end
Is each new goroutine called from the main goroutine or from the child goroutine?
func Request(retry bool) error { // request and verify license (external http service) err := verify_license() if err != nil { return err } if retry { // Renew verification timeout (renew license every 24 hours) time.AfterFunc(LICENSE_TIMEOUT, func(){ request_retry() }) } return nil } func request_retry(){ for i := 0; i < LICENSE_RETRY; i++ { if err := v.Request(false); err == nil { break } time.Sleep(LICENSE_RETRY_TIMEOUT) } time.Sleep(LICENSE_TIMEOUT) v.Request(true) }
if err := license_verify.Request(true); err != nil { log.Fatal(err.Error()) }
Maybe you can rethink the design of the problem. For example:
func main() { if !checkLicense() { log.Fatal("license check failed") } srv := http.Server{} // ctx, cancel := context.WithCancel(context.Background()) defer cancel() go func() { for { select { case <-ctx.Done(): // in case you want to instal signal handlers etc return case <-time.After(24 * time.Hour): if !checkLicense() { cancel() // or srv.Shtdown, really depends on you } } } }() if err := srv.ListenAndServe(); err != nil { log.Fatal(err) } } func checkLicense() bool { // add retries per request here }
Basically, what it does is create a goroutine that checks periodically and notifies the context or channel if something goes wrong.
If I understand the question correctly, you just need to keep it simple. One building block is to retry a request if it fails. Otherwise, there is a 24-hour retry. The final layer is to react to the check if it fails. You can use context, channel, or whatever you really like
The above is the detailed content of Goroutines called recursively by time.AfterFunc() are poorly designed. For more information, please follow other related articles on the PHP Chinese website!