package main
import (
"context"
"fmt"
"github.com/cloudflare/tableflip"
"io"
l "log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
var log = l.New(os.Stderr, "", l.LstdFlags|l.Llongfile)
func prefork(addr1, addr2 string) {
upg, err := tableflip.New(tableflip.Options{})
if err != nil {
panic(err)
}
defer upg.Stop()
// kill 升级
go func() {
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGHUP, syscall.SIGTERM)
for range sig {
if err := upg.Upgrade(); err != nil {
log.Println("Upgrade failed:", err)
continue
}
log.Println("Upgrade succeeded")
}
}()
ln, err := upg.Listen("tcp", "localhost:8080")
if err != nil {
log.Fatalln("Can't listen:", err)
}
var server http.Server
go server.Serve(ln)
// 退出清理
go func() {
<-upg.Exit()
_ = server.Shutdown(context.Background())
<-time.AfterFunc(time.Second*10, func() {
os.Exit(0)
}).C
}()
if err := upg.Ready(); err != nil {
panic(err)
}
select {}
}
// hello world, the web server
func HelloServer(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "hello, world!\n")
}
func main() {
http.HandleFunc("/hello", HelloServer)
fmt.Println(os.Getpid())
prefork(":8080", ":8081")
}
package main
import (
"fmt"
"io"
l "log"
"net"
"net/http"
"os"
"os/exec"
"os/signal"
"strings"
"syscall"
)
var log = l.New(os.Stderr, "", l.LstdFlags|l.Llongfile)
func isChild() bool {
for _, d := range os.Args {
if strings.Contains(d, "child") {
return true
}
}
return false
}
func prefork(addr1, addr2 string) (ln net.Listener, err error) {
var files []*os.File
if !isChild() {
{
// Master proc
addr, err := net.ResolveTCPAddr("tcp", addr1)
if err != nil {
log.Fatal(err)
return ln, err
}
tcplistener, err := net.ListenTCP("tcp", addr)
if err != nil {
log.Fatal(err)
return ln, err
}
fl, err := tcplistener.File()
if err != nil {
log.Fatal(err)
return ln, err
}
files = append(files, fl)
go func() {
server := &http.Server{Addr: "", Handler: nil}
if err := server.Serve(tcplistener); err != nil {
log.Fatal(err)
}
}()
}
{
// Master proc
addr, err := net.ResolveTCPAddr("tcp", addr2)
if err != nil {
return ln, err
}
tcplistener, err := net.ListenTCP("tcp", addr)
if err != nil {
return ln, err
}
fl, err := tcplistener.File()
if err != nil {
return ln, err
}
files = append(files, fl)
go func() {
server := &http.Server{Addr: addr2, Handler: nil}
if err := server.Serve(tcplistener); err != nil {
log.Fatal(err)
}
}()
}
}
if isChild() {
go func() {
f := os.NewFile(3, "")
listener, err := net.FileListener(f)
if err != nil {
log.Fatal(err)
}
server := &http.Server{Addr: "", Handler: nil}
if err := server.Serve(listener); err != nil {
log.Fatal(err)
}
}()
go func() {
f := os.NewFile(4, "")
listener, err := net.FileListener(f)
if err != nil {
log.Fatal(err)
}
server := &http.Server{Addr: "", Handler: nil}
if err := server.Serve(listener); err != nil {
log.Fatal(err)
}
}()
}
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGTERM)
fmt.Println(<-c)
childs := make([]*exec.Cmd, 1)
for i := range childs {
childs[i] = exec.Command(os.Args[0], append(os.Args[1:], "-prefork", "-child")...)
childs[i].Stdout = os.Stdout
childs[i].Stderr = os.Stderr
childs[i].ExtraFiles = files
if err := childs[i].Start(); err != nil {
log.Fatal(err)
return ln, err
}
}
for k := range childs {
if err := childs[k].Wait(); err != nil {
log.Fatal(err)
return ln, err
}
}
os.Exit(0)
return ln, err
}
// hello world, the web server
func HelloServer(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "hello, world!\n")
}
func main() {
http.HandleFunc("/hello", HelloServer)
//go http.ListenAndServe(":8080", nil)
//go http.ListenAndServe(":8081", nil)
fmt.Println(os.Getpid())
fmt.Println(prefork(":8080", ":8081"))
}
|
请发表评论