Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
89 lines
2.3 KiB
89 lines
2.3 KiB
// Copyright 2019 The Gitea Authors. All rights reserved. |
|
// Use of this source code is governed by a MIT-style |
|
// license that can be found in the LICENSE file. |
|
// This code is heavily inspired by the archived gofacebook/gracenet/net.go handler |
|
|
|
//go:build !windows |
|
// +build !windows |
|
|
|
package graceful |
|
|
|
import ( |
|
"fmt" |
|
"net" |
|
"os" |
|
"os/exec" |
|
"strings" |
|
"sync" |
|
"syscall" |
|
) |
|
|
|
var killParent sync.Once |
|
|
|
// KillParent sends the kill signal to the parent process if we are a child |
|
func KillParent() { |
|
killParent.Do(func() { |
|
if GetManager().IsChild() { |
|
ppid := syscall.Getppid() |
|
if ppid > 1 { |
|
_ = syscall.Kill(ppid, syscall.SIGTERM) |
|
} |
|
} |
|
}) |
|
} |
|
|
|
// RestartProcess starts a new process passing it the active listeners. It |
|
// doesn't fork, but starts a new process using the same environment and |
|
// arguments as when it was originally started. This allows for a newly |
|
// deployed binary to be started. It returns the pid of the newly started |
|
// process when successful. |
|
func RestartProcess() (int, error) { |
|
listeners := getActiveListeners() |
|
|
|
// Extract the fds from the listeners. |
|
files := make([]*os.File, len(listeners)) |
|
for i, l := range listeners { |
|
var err error |
|
// Now, all our listeners actually have File() functions so instead of |
|
// individually casting we just use a hacky interface |
|
files[i], err = l.(filer).File() |
|
if err != nil { |
|
return 0, err |
|
} |
|
|
|
if unixListener, ok := l.(*net.UnixListener); ok { |
|
unixListener.SetUnlinkOnClose(false) |
|
} |
|
// Remember to close these at the end. |
|
defer func(i int) { |
|
_ = files[i].Close() |
|
}(i) |
|
} |
|
|
|
// Use the original binary location. This works with symlinks such that if |
|
// the file it points to has been changed we will use the updated symlink. |
|
argv0, err := exec.LookPath(os.Args[0]) |
|
if err != nil { |
|
return 0, err |
|
} |
|
|
|
// Pass on the environment and replace the old count key with the new one. |
|
var env []string |
|
for _, v := range os.Environ() { |
|
if !strings.HasPrefix(v, listenFDs+"=") { |
|
env = append(env, v) |
|
} |
|
} |
|
env = append(env, fmt.Sprintf("%s=%d", listenFDs, len(listeners))) |
|
|
|
allFiles := append([]*os.File{os.Stdin, os.Stdout, os.Stderr}, files...) |
|
process, err := os.StartProcess(argv0, os.Args, &os.ProcAttr{ |
|
Dir: originalWD, |
|
Env: env, |
|
Files: allFiles, |
|
}) |
|
if err != nil { |
|
return 0, err |
|
} |
|
return process.Pid, nil |
|
}
|
|
|