Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 应用程序关闭时的通道和信号使用_Go_Signals_Channel - Fatal编程技术网

Go 应用程序关闭时的通道和信号使用

Go 应用程序关闭时的通道和信号使用,go,signals,channel,Go,Signals,Channel,下面的示例处理文档中描述的正常服务器关闭。在阅读了其他文章和示例后,基于我的研发工作,我提出了这项工作,它实际上优雅地关闭了服务器。然而,由于我在Golang的经验/知识非常有限,我无法证明我是否正确使用了通道和信号。我只是想避免Goroutine泄密和其他看不见的潜在问题。有人能告诉我这件作品是否是惯用的围棋代码以及通道和信号的用法吗 内部/server/server.go package server import ( "net/http" ) type Server struc

下面的示例处理文档中描述的正常服务器关闭。在阅读了其他文章和示例后,基于我的研发工作,我提出了这项工作,它实际上优雅地关闭了服务器。然而,由于我在Golang的经验/知识非常有限,我无法证明我是否正确使用了通道和信号。我只是想避免Goroutine泄密和其他看不见的潜在问题。有人能告诉我这件作品是否是惯用的围棋代码以及通道和信号的用法吗

内部/server/server.go

package server

import (
    "net/http"
)

type Server struct {
    *http.Server
}

func NewServer() Server {
    return Server{
        &http.Server{Addr: ":8080", Handler: nil},
    }
}

func (s Server) Start() error {
    if err := s.ListenAndServe(); err != http.ErrServerClosed {
        return err
    }

    return nil
}
package main

import (
    "api/internal/app"
    "api/internal/server"
    "context"
    "fmt"
    "os"
    "os/signal"
    "syscall"
)

func main() {
    // Some other bootstrapping and configuration code here ...
    // ....

    fmt.Printf("app starting")

    sigChan := make(chan os.Signal, 1)

    signal.Notify(sigChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)

    ctx, cancel := context.WithCancel(context.Background())

    go listenSignals(cancel, sigChan)

    if err := app.New(server.NewServer()).Start(ctx); err != nil {
        panic(err)
    }

    fmt.Print("app shutdown completed")
}

func listenSignals(cancel context.CancelFunc, sigChan chan os.Signal)  {
    sig := <-sigChan

    fmt.Printf("app shutdown started with %v signal", sig)

    cancel()
}
package app

import (
    "api/internal/server"
    "context"
    "errors"
    "fmt"
    "time"
)

type App struct {
    srv server.Server
}

func New(srv server.Server) App {
    return App{srv: srv}
}

func (app App) Start(ctx context.Context) error {
    doneChan := make(chan struct{})

    go shutdown(ctx, doneChan, app)

    // Start HTTP server    
    if err := a.srv.Start(); err != nil {
        return errors.New("failed to start HTTP server")
    }

    // Start DB server
    // ...

    <-doneChan

    return nil
}

func shutdown(ctx context.Context, doneChan chan<- struct{}, app App) {
    <-ctx.Done()

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    // Shutdown HTTP server  
    err := app.srv.Shutdown(ctx)
    if err != nil {
        fmt.Print("some active HTTP connections are interrupted at shutdown")
    } else {
        fmt.Print("no HTTP connections are interrupted at shutdown")
    }

    // Shutdown DB server
    // ...

    close(doneChan)
}
cmd/api/main.go

package server

import (
    "net/http"
)

type Server struct {
    *http.Server
}

func NewServer() Server {
    return Server{
        &http.Server{Addr: ":8080", Handler: nil},
    }
}

func (s Server) Start() error {
    if err := s.ListenAndServe(); err != http.ErrServerClosed {
        return err
    }

    return nil
}
package main

import (
    "api/internal/app"
    "api/internal/server"
    "context"
    "fmt"
    "os"
    "os/signal"
    "syscall"
)

func main() {
    // Some other bootstrapping and configuration code here ...
    // ....

    fmt.Printf("app starting")

    sigChan := make(chan os.Signal, 1)

    signal.Notify(sigChan, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)

    ctx, cancel := context.WithCancel(context.Background())

    go listenSignals(cancel, sigChan)

    if err := app.New(server.NewServer()).Start(ctx); err != nil {
        panic(err)
    }

    fmt.Print("app shutdown completed")
}

func listenSignals(cancel context.CancelFunc, sigChan chan os.Signal)  {
    sig := <-sigChan

    fmt.Printf("app shutdown started with %v signal", sig)

    cancel()
}
package app

import (
    "api/internal/server"
    "context"
    "errors"
    "fmt"
    "time"
)

type App struct {
    srv server.Server
}

func New(srv server.Server) App {
    return App{srv: srv}
}

func (app App) Start(ctx context.Context) error {
    doneChan := make(chan struct{})

    go shutdown(ctx, doneChan, app)

    // Start HTTP server    
    if err := a.srv.Start(); err != nil {
        return errors.New("failed to start HTTP server")
    }

    // Start DB server
    // ...

    <-doneChan

    return nil
}

func shutdown(ctx context.Context, doneChan chan<- struct{}, app App) {
    <-ctx.Done()

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    // Shutdown HTTP server  
    err := app.srv.Shutdown(ctx)
    if err != nil {
        fmt.Print("some active HTTP connections are interrupted at shutdown")
    } else {
        fmt.Print("no HTTP connections are interrupted at shutdown")
    }

    // Shutdown DB server
    // ...

    close(doneChan)
}
编辑 我做了一些goroutine分析,发现如下。我不确定结果是否正常!我需要你的意见

  • 对于
    运行时,单个请求的响应返回6。NumGoroutine()
    -pprof堆栈跟踪为。但是,如果我同时发送10个请求,则它介于1722之间
我不知道怎么读,所以有两个问题:

  • 对于一个请求,6个goroutine是否正常
  • 多个并发请求的增加正常吗?
    • 认为这是正常的,因为我正在使用
      httprouter
      ,它会对每个请求生效

  • 你没有泄漏任何goroutines。你正确地截获了信号。惯用的围棋?可能我倾向于为
    listenSignals
    之类的东西编写匿名函数,但我就是这样。感谢@sberry,如果堆栈跟踪查找有助于识别任何问题,我还会在文章的底部添加堆栈跟踪查找。