mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
Merge pull request #10765 from yousong/bugfix/yousong-ansibleserver-wait-zombie
ansibleserver: wait zombie subprocesses
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user