首頁  >  文章  >  後端開發  >  在 Uber FX 中實現後台進程正常關閉的正確方法是什麼?

在 Uber FX 中實現後台進程正常關閉的正確方法是什麼?

WBOY
WBOY轉載
2024-02-08 23:27:081143瀏覽

在 Uber FX 中实现后台进程正常关闭的正确方法是什么?

在Uber FX中,實作後台程序正常關閉的正確方法是什麼?這是許多人在使用Uber FX時經常遇到的問題。作為一個強大的後台任務處理框架,Uber FX提供了一種簡單而有效的方法來管理和處理後台任務。 php小編子墨將在本文中為您介紹如何正確關閉後台進程,確保程式的穩定性和正常運作。

問題內容

假設我的 Uber FX 應用程式中有一個服務,它應該執行一些後台活動,例如輪詢外部 API。 我可以透過觸發 goroutine 來運行後台任務,但是停止它們的正確方法是什麼?

作為一種可能的實現,讓我們考慮以下範例:

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()
}

一些注意事項:

  • 該服務透過使用 fx.Lifecycle 掛鉤連接到應用程式生命週期。
  • 我無法依賴和使用 OnStart/OnStop 方法中的上下文,因為它們是不同的上下文並且對應於啟動/停止活動,而不是應用生命週期上下文。

疑慮與問題:

  • 給出的範例在追蹤背景任務方面相當繁重。此外,將上下文儲存在結構中是一種反模式。有什麼辦法可以簡化嗎?
  • 如果沒有資源可以釋放,我是否應該等待完成 goroutine?

解決方法

在我看來,使用上下文就很好,但是您也可以透過通道向您想要的任何 Go 例程傳達關閉訊號。請參閱下面的範例程式碼。

是的,您還應該等待等待群組計數返回零,然後再完全關閉應用程式。所以你首先要關閉通道,然後在等待群組上等待。

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()
}

以上是在 Uber FX 中實現後台進程正常關閉的正確方法是什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除