2014-02-12 30 views
1

我正在嘗試falcore(去(郎)框架),他們有一個很好的例子,允許你發送一個SIGHUP的過程,之後它重新啓動客戶端,移動連接並退出父級。falcore熱啓動不重新加載主代碼

因此,在我的示例中,我有一個server.go(發佈在最後),默認情況下服務於一個文件。

我運行服務器,然後編輯.go文件,kill -1進程的pid,然後應用程序按預期重新啓動,但新加入的.go文件代碼未加載。

例如,我將從summary.xml提供的默認文件更改爲AppNexus-Interesting.txt,但它將繼續爲所有新請求提供summary.xml文件。

任何幫助表示讚賞。

package main 

import (
    "flag" 
    "fmt" 
    "github.com/fitstar/falcore" 
    "github.com/fitstar/falcore/filter" 
    "net/http" 
    "os" 
    "os/signal" 
    "syscall" 
) 

// Command line options 
var (
    port = flag.Int("port", 8000, "the port to listen on") 
    path = flag.String("base", "./www", "the path to serve files from") 
) 

// very simple request filter 
func Filter(req *falcore.Request) *http.Response { 
    pid := syscall.Getpid() 
    fmt.Println(pid, "GET", req.HttpRequest.URL.Path) 

    // return falcore.StringResponse(request.HttpRequest, 200, nil, "OK\n") 
    if req.HttpRequest.URL.Path == "/" { 
     req.HttpRequest.URL.Path = "AppNexus-Interesting.txt" //"/summary.xml" 
    } 
    return nil 
} 

// flag to accept a socket file descriptor 
var socketFd = flag.Int("socket", -1, "Socket file descriptor") 

func main() { 
    pid := syscall.Getpid() 
    flag.Parse() 
    fmt.Println("Falcore hot restart running with pid:", pid, "to hot restart, issue the kill -1", pid, "command") 

    // create the pipeline 
    pipeline := falcore.NewPipeline() 

    // upstream filters 
    pipeline.Upstream.PushBack(falcore.NewRequestFilter(Filter)) 

    // Serve files 
    pipeline.Upstream.PushBack(&filter.FileFilter{ 
     BasePath: *path, 
    }) 

    // downstream filters 
    pipeline.Downstream.PushBack(filter.NewCompressionFilter(nil)) 

    // create the server with the pipeline 
    srv := falcore.NewServer(*port, pipeline) 

    // if passed the socket file descriptor, setup the listener that way 
    // if you don't have it, the default is to create the socket listener 
    // with the data passed to falcore.NewServer above (happens in ListenAndServer()) 
    if *socketFd != -1 { 
     // I know I'm a child process if I get here so I can signal the parent when I'm ready to take over 
     go childReady(srv) 
     fmt.Printf("%v Got socket FD: %v\n", pid, *socketFd) 
     srv.FdListen(*socketFd) 
    } 

    // using signals to manage the restart lifecycle 
    go handleSignals(srv) 

    // start the server 
    // this is normally blocking forever unless you send lifecycle commands 
    if err := srv.ListenAndServe(); err != nil { 
     fmt.Printf("%v Could not start server: %v", pid, err) 
    } 
    fmt.Printf("%v Exiting now\n", pid) 
} 

// blocks on the server ready and when ready, it sends 
// a signal to the parent so that it knows it cna now exit 
func childReady(srv *falcore.Server) { 
    pid := syscall.Getpid() 
    // wait for the ready signal 
    <-srv.AcceptReady 
    // grab the parent and send a signal that the child is ready 
    parent := syscall.Getppid() 
    fmt.Printf("%v Kill parent %v with SIGUSR1\n", pid, parent) 
    syscall.Kill(parent, syscall.SIGUSR1) 
} 

// setup and fork/exec myself. Make sure to keep open important FD's that won't get re-created by the child 
// specifically, std* and your listen socket 
func forker(srv *falcore.Server) (pid int, err error) { 
    fmt.Printf("Forking now with socket: %v\n", srv.SocketFd()) 
    mypath := os.Args[0] 
    args := []string{mypath, "-socket", fmt.Sprintf("%v", srv.SocketFd())} 
    attr := new(syscall.ProcAttr) 
    attr.Files = append([]uintptr(nil), 0, 1, 2, uintptr(srv.SocketFd())) 
    pid, err = syscall.ForkExec(mypath, args, attr) 
    return 
} 

// Handle lifecycle events 
func handleSignals(srv *falcore.Server) { 
    var sig os.Signal 
    var sigChan = make(chan os.Signal) 
    signal.Notify(sigChan, syscall.SIGHUP, syscall.SIGUSR1, syscall.SIGINT, syscall.SIGTERM, syscall.SIGTSTP) 
    pid := syscall.Getpid() 
    for { 
     sig = <-sigChan 
     switch sig { 
     case syscall.SIGHUP: 
      // send this to the paraent process to initiate the restart 
      fmt.Println(pid, "Received SIGHUP. forking.") 
      cpid, err := forker(srv) 
      fmt.Println(pid, "Forked pid:", cpid, "errno:", err) 
     case syscall.SIGUSR1: 
      // child sends this back to the parent when it's ready to Accept 
      fmt.Println(pid, "Received SIGUSR1. Stopping accept.") 
      srv.StopAccepting() 
     case syscall.SIGINT: 
      fmt.Println(pid, "Received SIGINT. Shutting down.") 
      os.Exit(0) 
     case syscall.SIGTERM: 
      fmt.Println(pid, "Received SIGTERM. Terminating.") 
      os.Exit(0) 
     case syscall.SIGTSTP: 
      fmt.Println(pid, "Received SIGTSTP. Stopping.") 
      syscall.Kill(pid, syscall.SIGSTOP) 
     default: 
      fmt.Println(pid, "Received", sig, ": ignoring") 
     } 
    } 
} 
+0

你重新編譯了你的服務器二進制文件嗎? Go不是一種腳本語言,因此您必須將源代碼編譯爲二進制文件(使用'go build'或'go install'),然後執行重新啓動。 – mechmind

+0

它工作:)我做'去建立server.go',然後以'./ server'開始,編輯server.go文件,做另一個'去建立server.go',然後'kill -1 ',現在它工作。謝謝:)發表回答,我會接受。 –

回答

1

由於走的是不是一種腳本語言,你必須編譯成二進制第一(使用go buildgo install)來源,然後執行重新啓動。

相關問題