Giter Site home page Giter Site logo

ramr / go-reaper Goto Github PK

View Code? Open in Web Editor NEW
115.0 115.0 16.0 27 KB

Process (Grim) reaper library for golang - this is useful for cleaning up zombie processes inside docker containers (which do not have an init process running as pid 1).

License: MIT License

Makefile 8.83% Go 91.17%

go-reaper's People

Contributors

ramr avatar s3rj1k avatar sergeyklay avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

go-reaper's Issues

I met some problem

for {
var sig = <-notifications
fmt.Printf(" - Received signal %v\n", sig)
for {
var wstatus syscall.WaitStatus

        /*
         *  Reap 'em, so that zombies don't accumulate.
         *  Plants vs. Zombies!!
         */
        pid, err := syscall.Wait4(-1, &wstatus, 0, nil)
        for syscall.EINTR == err {
            pid, err = syscall.Wait4(-1, &wstatus, 0, nil)
        }

        if syscall.ECHILD == err {
            break
        }

        fmt.Printf(" - Grim reaper cleanup: pid=%d, wstatus=%+v\n",
            pid, wstatus)
                  // I think  it should be break here
                 break;
    }
}

Question: Does a race condition exist in the "Into the woods" implementation?

I may be wrong here but is there a race condition present in the "Into the woods" implementation?
We wait4 on the child pid we fork in the parent as a means to block so we don't kill pid1 until our forked process exits. Great. However, when that original child eventually dies, it is possible (dependent upon context switching within the go runtime) that the wait4 in reapChild (line 61) may handle that exit before the original wait4 in the main thread. In this case I think pid 1 won't ever exit because it will be waiting on a pid that had already reaped by the reaper. Thoughts?

wait: no child processes

When trying go-reaper in a service at work, we're getting this error:

Jul 21 11:27:28 app01 docker/doc-view-service.01[677]:  - Received signal child exited
Jul 21 11:27:28 app01 docker/doc-view-service.01[677]:  - Grim reaper cleanup: pid=701, wstatus=0
Jul 21 11:27:28 app01 docker/doc-view-service.01[677]:  - Grim reaper cleanup: pid=685, wstatus=0
Jul 21 11:27:28 app01 docker/doc-view-service.01[677]: 2017/07/21 10:27:28 http: panic serving 172.16.0.38:40850: wait: no child processes
Jul 21 11:27:28 app01 docker/doc-view-service.01[677]: goroutine 22346444 [running]:

This looks quite similar to this issue on gitlab-ci-multi-runner:

https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/issues/989

Our code calls cmd.Run(), so I think what's happening is that the process is getting cleaned up by the reaper before cmd.Wait() can reach it, but I need to debug it further.

seeing error "waitid: no child processes" from run-to-completion processes while reaping

Similar to #2 but a little different.

After doing go reaper.Reap() in my program, I'm doing simple run-to-completion executions, such as:

cmd := exec.Command("some-cmd")
b, err := cmd.CombinedOutput()

this is returning error

waitid: no child processes

When I do not do go reaper.Reap(), things seem to work fine.

For example, more weirdly, this happens only while running:

{/bin/sh [-c npm install --only=production]}

but not while running:

{/bin/sh [-c go build .]}

I have a suspicion that these two commands are different somehow.

How to debug this?

wait: no child processes

I use https://github.com/ramr/go-reaper#into-the-woods method to resolve but it's not work

my test code

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"github.com/ramr/go-reaper"
	"os"
	"syscall"
	"time"
)

func main() {

	config := reaper.Config{
		Pid:              -1,
		Options:          0,
		Debug:            true,
		DisablePid1Check: false,
	}

	//  Start background reaping of orphaned child processes.
	go reaper.Start(config)
	go func() {
		err := forkForeground([]string{"/usr/bin/supervisord", "-n", "-c", "/etc/supervisor/supervisord.conf"})
		fmt.Println(err)
	}()

	go func() {
		for {
			select {
			case <-time.After(100 * time.Millisecond):
				fmt.Println(forkExecRunOnce([]string{"/usr/bin/supervisorctl", "-c", "/etc/supervisor/supervisord.conf", "status", "nginx"}))
			}
		}
	}()

	time.Sleep(1 * time.Hour)
}

func forkExecRunOnce(xargs []string) (string, string) {

	stdout := &bytes.Buffer{}
	stderr := &bytes.Buffer{}

	forkExec(xargs, func(stdoutFile *os.File, stderrFile *os.File, waitChan chan error) {

		defer stdoutFile.Close()
		defer stderrFile.Close()
		defer close(waitChan)

		err := <-waitChan
		if err != nil {
			fmt.Println(err)
		}
		buf := bufio.NewReader(stdoutFile)
		for {
			if l, _, err := buf.ReadLine(); err == nil {
				fmt.Println(string(l))
			} else {
				break
			}
		}
		buf = bufio.NewReader(stderrFile)
		for {
			if l, _, err := buf.ReadLine(); err == nil {
				fmt.Println(string(l))
			} else {
				break
			}
		}
	})
	return stdout.String(), stderr.String()
}

func forkForeground(xargs []string) error {
	var status syscall.WaitStatus
	attrs := &syscall.ProcAttr{
		Env: append(os.Environ()),
		Sys: &syscall.SysProcAttr{
			Setsid: true,
		},
		Files: []uintptr{
			0, 1, 2,
		},
	}
	pid, _ := syscall.ForkExec(xargs[0], xargs, attrs)
	_, err := syscall.Wait4(pid, &status, 0, nil)

	return err

}

func forkExec(xargs []string, call func(*os.File, *os.File, chan error)) {
	readOut, writeOut, _ := os.Pipe()
	readErr, writeErr, _ := os.Pipe()

	var wstatus syscall.WaitStatus
	pattrs := &syscall.ProcAttr{
		Env: append(os.Environ()),
		Sys: &syscall.SysProcAttr{
			Setsid: true,
		},
		Files: []uintptr{
			0, writeOut.Fd(), writeErr.Fd(),
		},
	}
	pid, err := syscall.ForkExec(xargs[0], xargs, pattrs)
	if err != nil {
		fmt.Println(err)
	}

	waitChan := make(chan error)

	go func() {
		_, err := syscall.Wait4(pid, &wstatus, 0, nil)
		if err != nil {
			fmt.Println(wstatus.Stopped())
		}

		writeOut.Close()
		writeErr.Close()
		waitChan <- err
	}()

	// call user func
	go call(readOut, readErr, waitChan)

}

go build main.go and run in docker

docker run -it --rm --name test  -v /home/sre/test/:/tmp  okteto/supervisord-nginx  /tmp/main

wait 10 seconds and print log

nginx                            STARTING
 - Received signal child exited

false
 - Grim reaper cleanup: pid=18, wstatus=0
no child processes
nginx                            STARTING

false
 - Grim reaper cleanup: pid=86, wstatus=0
no child processes
nginx                            STARTING

false
 - Grim reaper cleanup: pid=88, wstatus=0
no child processes
nginx                            STARTING

false
 - Grim reaper cleanup: pid=89, wstatus=0
no child processes
nginx                            STARTING

false
 - Grim reaper cleanup: pid=91, wstatus=0
no child processes
nginx                            STARTING

nginx                            STARTING

nginx                            STARTING

nginx                            STARTING

so I think into-the-woods it's not work

Test for notifications

Check if getting notifications on new issues.
Though the test might be off as "I am he and you are he" ... goo goo g'joob!!

Make a release version

Hi,
Could you make a release version so that I hold a particular version in my go.mod?
Thanks

Why is this package needed?

If everything you want to do is just reap any zombies, then it is much easier to just do:

signal.Ignore(syscall.SIGCHLD)

By explicitly setting SIGCHLD handler to ignore, you ask Linux to reap zombies for us. This then handles zombies for you. No need to make a loop and wait yourself.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.