Golang Hot Restart

Source: Internet
Author: User
What is a hot restart:

The new and old programs (processes) are seamlessly replaced, while maintaining the service to the client. Let the client side not feel your service hangs off. such as reloading the configuration file, need to reboot, replace the old program need to reboot, you need to use a hot restart. However, the use of golang scenes, in fact, directly at the HTTP proxy level to make cut traffic more convenient. principle

interacts with processes by sending signal (signals). The signal can be defined by itself, specifying the signal of the interception system, changing the system default behavior to customize the operation.

If you receive a restart signal, fork the new version of the process to hand the socket handle to the new process, the new process starts accepting the new connection request the old version server to stop accepting the connection, to maintain the existing connection, stop the old version of the server immediately after processing, turn off the monitoring (OS. Exit (1)). a simplified version of the restart process

My code here does not deal with the original connection, easy to understand the key points, you can refer to other articles with sync. Waitgroup.wait () to deal with this problem. generate a server to listen on 8888 ports, then intercept system signals, get listeners

Get the listener, here with a function to get, because the parent process and the child process gets to the listener is not the same, the parent process gets the original TCP socket file, and the child process gets only the copy of the socket file. Well, if you get a TCP socket file twice, which is equivalent to listening to the same port 2 times, this error will be reported listen tcp:8888:bind:address already in use. Therefore, the second acquisition of a copy is equivalent to inheriting the parent listener. This is the key point for the thermal restart.

Func Main () {

    Server = http. server{
        Addr:        ": 8888",
        Handler:     &myhandle{},
        Readtimeout:6 * time. Second,
    }

    go handlesignals ()

    log. Printf ("Actual pid is%d\n", Syscall. Getpid ())

    var err2 error

    Listener, ERR2 = Getlistener (server. ADDR)

    if err2! = nil {
        log. Println (ERR2)

    }

    log. Printf ("IsChild:%v, Listener:%v\n", IsChild, listener)

    ERR: = Server. Serve (listener)

    if err! = Nil {
        log. PRINTLN (Err)
    }
}
getting the socket listener and inheriting the socket listener

IsChild is the flag of the child process, if it is a child process  f: = OS. NewFile (3, ""), why is 3, instead of 1 0 or other numbers. This is because the parent process has given a FD to the child process and the child process 0,1,2 is reserved for standard input, output, and error, so the parent process gives the first FD in the sub-process sequence is starting from 3, if the fork when the CMD. Extrafiles gave two file handle, then the child process can also start with 4, it depends on how many children you have to increase the number of processes from the line. Because I have a sub-process here, so I wrote 3 dead. L, err = net. Filelistener (f) This step simply wraps the FD descriptor into the tcplistener structure.

Func Getlistener (Laddr string) (l net. Listener, err Error) {
        If ischild {

            runningserverreg.rlock ()
            defer runningserverreg.runlock ()

            f: = OS. NewFile (3, "")

            l, err = net. Filelistener (f)
            if err! = Nil {
                log. Printf ("net. Filelistener error: ", err)
                return
            }

            log. Printf ("LADDR:%v, listener:%v \ n", Laddr, L)

            Syscall. Kill (Syscall. Getppid (), Syscall. SIGTSTP)//Kill parent Process

        } else {
            L, err = net. Listen ("TCP", LADDR)
            if err! = Nil {
                log. Printf ("net. Listen error:%v ", err)
                return}}
        return
}
Signal Processing

Signal with a signal bag. Notify filters out the signals that they want to define and releases them. Sighup is used to fork the child process, SIGTSTP to kill the parent process. SIGINT is used for its own ctr+c, convenient to interrupt the test.

Func handlesignals () {
    var sig os. Signal

    Signal. Notify (
        Sigchan,
        hookablesignals ...,
    )

    pid: = Syscall. Getpid () for

    {
        sig = <-sigchan
        log. PRINTLN (PID, "Received sig.", SIG)
        switch sig {case
        syscall. SIGHUP:
            log. PRINTLN (PID, "Received SIGHUP. Forking. ")
            ERR: = Fork ()
            if err! = Nil {
                log. Println ("Fork err:", err)
            } case
        Syscall. SIGTSTP:
            log. PRINTLN (PID, "Received sigtstp.")
            Shutdown ()
        default:
            log. Printf ("Received%v \ n", Sig)}}

Fork Sub-process

Cmd. Extrafiles = []*os. FILE{FL} is the key to implementing the underlying socket service

Func fork () (err error) {
        runningserverreg.lock ()

        defer runningserverreg.unlock ()

        if runningserversforked {
            return errors. New ("another process already forked. Ignoring this one. ")
        }

        runningserversforked = True

        log. Println ("restart:forked Start ...")

        TL: = Listener. ( *net. TcpListener)
        fl, _: = TL. File ()

        path: = OS. Args[0]
    
        cmd: = Exec.command (path, []string{"-continue"})
        cmd. Stdout = OS. Stdout
        cmd. Stderr = OS. Stderr
        cmd. Extrafiles = []*os. FILE{FL}//Inherited listener file

        err = cmd. Start ()//fork, not immediately execute
        if err! = Nil {
            log. Printf ("Restart:failed to launch, error:%v", err)
        }

        return
}

There is also a way to fork, as in the essence of the above:

Execspec: = &syscall. procattr{
    ENV:   os. Environ (),
    Files: []uintptr{os. STDIN.FD (), OS. STDOUT.FD (), OS. STDERR.FD (), lFd},
}
pid, err: = Syscall. Forkexec (OS. ARGS[0], OS. Args, Execspec)
Close Parent Process

In fact, a first check there is no active connection, the service must be completed before switching off, with sync. Waitgroup.wait () to block is a good way, I do not write these in order to demonstrate the fork section.

Func shutdown () {
    log. Printf ("Shutdown Listener:%v\n", Listener)
    err: = Listener. Close ()

    if err! = Nil {
        log. Println (Syscall. Getpid (), "Listener.close () Error:", err)
    } else {
        log. Println (Syscall. Getpid (), server. ADDR, "Listener closed.")
    }

    Os. Exit (1)
}
The magical magic of flag package

Flag package can automatically parse various command line parameters, more simple than the analysis of the string itself, must flag. Parse () to begin parsing.

Func init () {
    flag. Boolvar (&ischild, "continue", false, "Listen on open fd (after forking)")
    flag. Parse ()
 }
source code has been uploaded

Https://github.com/jeffdeng/gracefullDemo

If you want to open the box, you can use this Https://github.com/tim1020/godaemon or this https://github.com/fvbock/endless, of course, understand the principle is the most important. Reference:

http://my.oschina.net/tim8670/blog/643966

http://grisha.org/blog/2014/06/03/graceful-restart-in-golang/

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.