Maison > Article > développement back-end > Quelle est la bonne manière d'obtenir un arrêt progressif des processus en arrière-plan dans Uber FX ?
Quelle est la bonne façon d'obtenir un arrêt progressif des processus en arrière-plan dans Uber FX ? Il s'agit d'un problème courant que de nombreuses personnes rencontrent lors de l'utilisation d'Uber FX. En tant que puissant framework de traitement des tâches en arrière-plan, Uber FX fournit un moyen simple et efficace de gérer et de traiter les tâches en arrière-plan. Dans cet article, l'éditeur PHP Zimo vous présentera comment fermer correctement le processus en arrière-plan pour assurer la stabilité et le fonctionnement normal du programme.
Supposons que j'ai un service dans mon application Uber FX qui est censé effectuer une activité en arrière-plan, telle que l'interrogation d'une API externe. Je peux exécuter des tâches en arrière-plan en déclenchant une goroutine, mais quelle est la bonne façon de les arrêter ?
Comme implémentation possible, considérons l'exemple suivant :
package main import ( "context" "log" "sync" "time" "go.uber.org/fx" ) type AwesomeService struct { // context to use for background processes bg context.Context // to trigger background processes stopping cancel context.CancelFunc // to wait for background processes to gracefully finish wg *sync.WaitGroup } func New(lc fx.Lifecycle) *AwesomeService { bg, cancel := context.WithCancel(context.Background()) service := &AwesomeService{ bg: bg, cancel: cancel, wg: new(sync.WaitGroup), } lc.Append(fx.Hook{ OnStart: service.start, OnStop: service.stop, }) return service } func (s *AwesomeService) start(_ context.Context) error { s.runBackgroundProcess() log.Println("Start done") return nil } func (s *AwesomeService) stop(_ context.Context) error { s.cancel() s.wg.Wait() log.Println("Stop done") return nil } // runBackgroundProcess does some work till context is done. func (s *AwesomeService) runBackgroundProcess() { s.wg.Add(1) go func() { defer s.wg.Done() for { select { case <-s.bg.Done(): return case <-time.After(1 * time.Second): log.Println("Working...") } } }() } func main() { fx.New( fx.Provide(New), fx.Invoke(func(*AwesomeService) {}), ).Run() }
Quelques remarques :
fx.Lifecycle
hooks. OnStart
/OnStop
car ce sont des contextes différents et correspondent aux activités de démarrage/arrêt, et non au contexte du cycle de vie de l'application. Préoccupations et questions :
À mon avis, utiliser un contexte est très bien, mais vous pouvez également communiquer un signal d'arrêt via un canal à n'importe quelle routine Go de votre choix. Voir l'exemple de code ci-dessous.
Oui, vous devez également attendre que le nombre de groupes d'attente revienne à zéro avant de fermer complètement l'application. Vous fermez donc d’abord la chaîne, puis attendez le groupe d’attente.
package main import ( "context" "log" "sync" "time" "go.uber.org/fx" ) type AwesomeService struct { // channel to shutdown background processes shutdown chan struct{} // to wait for background processes to gracefully finish wg *sync.WaitGroup } func New(lc fx.Lifecycle) *AwesomeService { service := &AwesomeService{ shutdown: make(chan struct{}), wg: new(sync.WaitGroup), } lc.Append(fx.Hook{ OnStart: service.start, OnStop: service.stop, }) return service } func (s *AwesomeService) start(_ context.Context) error { s.runBackgroundProcess() log.Println("Start done") return nil } func (s *AwesomeService) stop(_ context.Context) error { close(s.shutdown) s.wg.Wait() log.Println("Stop done") return nil } // runBackgroundProcess does some work till context is done. func (s *AwesomeService) runBackgroundProcess() { s.wg.Add(1) go func() { defer s.wg.Done() for { select { case <-s.shutdown: return case <-time.After(1 * time.Second): log.Println("Working...") } } }() } func main() { fx.New( fx.Provide(New), fx.Invoke(func(*AwesomeService) {}), ).Run() }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!