Merge pull request #10765 from yousong/bugfix/yousong-ansibleserver-wait-zombie

ansibleserver: wait zombie subprocesses
This commit is contained in:
Zexi Li
2021-04-16 13:15:17 +08:00
committed by GitHub
2 changed files with 121 additions and 0 deletions
+3
View File
@@ -15,6 +15,7 @@
package service
import (
"context"
"os"
_ "github.com/go-sql-driver/mysql"
@@ -48,5 +49,7 @@ func StartService() {
db.EnsureAppInitSyncDB(app, dbOpts, models.InitDB)
defer cloudcommon.CloseDB()
go ReapZomebieLoop(context.TODO())
common_app.ServeForever(app, baseOpts)
}
+118
View File
@@ -0,0 +1,118 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package service
import (
"context"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
"yunion.io/x/log"
)
func ReapZomebieLoop(ctx context.Context) {
myPid := os.Getpid()
if myPid != 1 {
log.Infof("My pid is not 1 and no need to wait zombies")
return
}
myPidStr := fmt.Sprintf("%d", myPid)
tick := time.NewTicker(31 * time.Second)
for {
dirs, err := ioutil.ReadDir("/proc")
if err != nil {
log.Errorf("read /proc dir: %v", err)
}
for _, dir := range dirs {
// /proc/<pid>/
if !dir.IsDir() {
continue
}
name := dir.Name()
allDigits := true
for _, c := range name {
if c < '0' || c > '9' {
allDigits = false
break
}
}
if !allDigits {
continue
}
// read /proc/<pid>/stat
statPath := filepath.Join("/proc", name, "stat")
data, err := ioutil.ReadFile(statPath)
if err != nil {
log.Errorf("read %s: %v", statPath, err)
continue
}
dataStr := string(data)
items := strings.Split(dataStr, " ")
const (
idxPid = iota
idxName = iota
idxState = iota
idxPpid = iota
idxMinLen = iota
)
if len(items) < idxMinLen {
log.Errorf("%s contains less than %d items: %s", statPath, idxMinLen, dataStr)
}
// my zombie subprocesses
state := items[idxState]
if state != "Z" {
continue
}
ppidStr := items[idxPpid]
if ppidStr != myPidStr {
continue
}
// wait it
pname := items[idxName]
pidStr := items[idxPid]
pid, err := strconv.Atoi(pidStr)
if err != nil {
log.Errorf("%s: %s has invalid pid number %q: %v", pname, statPath, pidStr, err)
continue
}
var (
status syscall.WaitStatus
rusage syscall.Rusage
)
pid1, err := syscall.Wait4(pid, &status, 0, &rusage)
if err != nil {
log.Errorf("%s: %s: wait error: %v", pname, statPath, err)
continue
}
if pid1 == pid {
log.Infof("%s: pid %d: wait done", pname, pid)
}
}
select {
case <-ctx.Done():
case <-tick.C:
}
}
}