Giter Club home page Giter Club logo

goproc's Introduction

goproc

Simple process manager helper library, features:

  • start processes .AddCommand(Cmd) and .Start(cmdId) or .StartAll(), with environment variables Cmd.Env=[]string{} and Cmd.InheritEnv=true
  • stop them; .Kill(cmdId) or .Cleanup() to kill all process
  • restart them when they crash; using Cmd.RestartDelayMs=1000 (=1s, default is 0) and Cmd.MaxRestart=5 (restart 5x if process ended/crashed)
  • relay termination signals; .Signal(cmdId, os.Kill)
  • read their stdout and stderr; Cmd.OnStdout, Cmd.OnStdErr callback
  • ability to stop processes when main processes are SIGKILL'ed: .Cleanup() called automatically when main process killed;
  • configurable backoff strategy for restarts; you can use Cmd.OnRestart callback to return random delay or implement your own exponential backoff, setting this callback will render Cmd.RestartDelayMs unusable
  • Cmd.OnExit callback when no more restart reached, you can call .Start(cmdId) manually again after this
  • Cmd.OnProcessCompleted callback each time program completed once (before restarting if MaxRestart not yet reached)
  • Cmd.StartDelayMs=1000 (=1s, default is 0) for delaying start, in milliseconds
  • Cmd.UseChannelApi=true, if enabled, you can receive from channels: Cmd.StderrChannel, Cmd.OnStdoutChannel, Cmd.ProcessCompletedChannel, Cmd.ExitChannel
  • Cmd.LastExecutionError property to get last process execution error, check this answer to get the exit code
  • Cmd.OnStateChanged callback and Cmd.StateChangedChannel channel to track process state
  • should work on Linux, and probably MacOS and Windows (untested).
  • see example/ for other usage example/demo;

Versioning

versioning using this format 1.(M+(YEAR-2021)*12)DD.HMM, so for example v1.213.1549 means it was released at 2021-02-13 15:49

Example

daemon := goproc.New()

cmdId := daemon.AddCommand(&goproc.Cmd{
    Program: `sleep`, // program to run
	WorkDir: `/tmp`, // directory to run the program (optional)
    Parameters: []string{`2`}, // command line arguments
    MaxRestart: goproc.RestartForever, // default: NoRestart=0
    OnStderr: func(cmd *goproc.Cmd, line string) error { // optional
        fmt.Println(`OnStderr: `+line)
        return nil
    },
    OnStdout: func(cmd *goproc.Cmd, line string) error { // optional
        fmt.Println(`OnStdout: `+line)
        return nil
    },
})

daemon.Start(cmdId) // use "go" keyword if you need non-blocking version
// ^ by default will only run next command if previous command exited
// if you want to run them in parralel, use daemon.StartParallel().Wait()

daemon.CommandString(cmdId) // returns "sleep 2"

FAQ

Q: Why not just channel? why callback?

A: Because channel requires a consumer, or it would stuck/block if channel is full, while callback doesn't (this is why I add flag to activate the channel API). To the Percona reviewer that rejected me because I didn't use channel at the first time "the whole thing is written in JavaScript translated to Go, not in Go. Technical task does not adhere to Go best practices which is what would expect from the candidate. One example was that the code is written in JS-like style (e.g. callback). Go code does not use callback like node.js for example", well, jokes on you even net/http.HandleFunc uses callback XD

Q: How to ignore error being printed?

A: assign Goproc.HasErrFunc with goproc.DiscardHasErr, other option are: L.IsError (default), goproc.LogHasErr (uses log), goproc.PrintHasErr (uses fmt), or you can always create your own.

TODO

  • implement .Pause and .Resume API
  • comments and documentation in code;
  • continuous integration configuration;
  • integration tests;
  • unit tests.

goproc's People

Contributors

dependabot[bot] avatar kokizzu 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

Watchers

 avatar  avatar

goproc's Issues

Error

  • Input </root/jancox/input.zip>
  • Extracting ZIP
  • Extracting system_ext.new.dat.br to /root/jancox/bin/flashable/system_ext.new.dat
    system
    2021/12/16 09:04:21 CMD:0: starting: /usr/bin/python "/root/jancox/bin/sdat2img/sdat2img.py" "/root/jancox/bin/flashable/system.transfer.list" "/root/jancox/bin/flashable/system.new.dat" "/root/jancox/bin/tmp/system.img"
    2021/12/16 09:04:21 CMD:0: sdat2img binary - version: 1.0
    2021/12/16 09:04:21 CMD:0:
    2021/12/16 09:04:21 CMD:0: Traceback (most recent call last):
    2021/12/16 09:04:21 CMD:0: File "/root/jancox/bin/sdat2img/sdat2img.py", line 142, in
    2021/12/16 09:04:21 CMD:0: main(sys.argv)
    2021/12/16 09:04:21 CMD:0: File "/root/jancox/bin/sdat2img/sdat2img.py", line 87, in main
    2021/12/16 09:04:21 CMD:0: version, new_blocks, commands = parse_transfer_list_file(TRANSFER_LIST_FILE)
    2021/12/16 09:04:21 CMD:0: File "/root/jancox/bin/sdat2img/sdat2img.py", line 55, in parse_transfer_list_file
    2021/12/16 09:04:21 CMD:0: trans_list = open(TRANSFER_LIST_FILE, 'r')
    2021/12/16 09:04:21 CMD:0: IOError: [Errno 2] No such file or directory: '/root/jancox/bin/flashable/system.transfer.list'
    2021-12-16 09:04:21.794 IsError ▶ ot/go/pkg/mod/github.com/kokizzu/[email protected]/goproc.go:301: github.com/kokizzu/goproc.(*Goproc).Start: CMD:0: error proc.exe.Wait /usr/bin/python "/root/jancox/bin/sdat2img/sdat2img.py" "/root/jancox/bin/flashable/system.transfer.list" "/root/jancox/bin/flashable/system.new.dat" "/root/jancox/bin/tmp/system.img"
    2021-12-16 09:04:21.795 IsError ▶ &exec.ExitError{
    ProcessState: &os.ProcessState{
    pid: 25203,
    status: 0x100,
    rusage: &syscall.Rusage{
    Utime: syscall.Timeval{Sec:0, Usec:49818},
    Stime: syscall.Timeval{Sec:0, Usec:22720},
    Maxrss: 6124,
    Ixrss: 0,
    Idrss: 0,
    Isrss: 0,
    Minflt: 900,
    Majflt: 1,
    Nswap: 0,
    Inblock: 256,
    Oublock: 0,
    Msgsnd: 0,
    Msgrcv: 0,
    Nsignals: 0,
    Nvcsw: 661,
    Nivcsw: 6,
    },
    },
    Stderr: nil,
    }
    2021-12-16 09:04:21.796 IsError ▶ &exec.ExitError{
    ProcessState: &os.ProcessState{
    pid: 25203,
    status: 0x100,
    rusage: &syscall.Rusage{
    Utime: syscall.Timeval{Sec:0, Usec:49818},
    Stime: syscall.Timeval{Sec:0, Usec:22720},
    Maxrss: 6124,
    Ixrss: 0,
    Idrss: 0,
    Isrss: 0,
    Minflt: 900,
    Majflt: 1,
    Nswap: 0,
    Inblock: 256,
    Oublock: 0,
    Msgsnd: 0,
    Msgrcv: 0,
    Nsignals: 0,
    Nvcsw: 661,
    Nivcsw: 6,
    },
    },
    Stderr: nil,
    }
    StackTrace:
    2021/12/16 09:04:21 CMD:0: max restart reached 0
    vendor
    2021/12/16 09:04:21 CMD:0: starting: /usr/bin/python "/root/jancox/bin/sdat2img/sdat2img.py" "/root/jancox/bin/flashable/vendor.transfer.list" "/root/jancox/bin/flashable/vendor.new.dat" "/root/jancox/bin/tmp/vendor.img"
    2021/12/16 09:04:22 CMD:0: sdat2img binary - version: 1.0
    2021/12/16 09:04:22 CMD:0:
    2021/12/16 09:04:22 CMD:0: Traceback (most recent call last):
    2021/12/16 09:04:22 CMD:0: File "/root/jancox/bin/sdat2img/sdat2img.py", line 142, in
    2021/12/16 09:04:22 CMD:0: main(sys.argv)
    2021/12/16 09:04:22 CMD:0: File "/root/jancox/bin/sdat2img/sdat2img.py", line 87, in main
    2021/12/16 09:04:22 CMD:0: version, new_blocks, commands = parse_transfer_list_file(TRANSFER_LIST_FILE)
    2021/12/16 09:04:22 CMD:0: File "/root/jancox/bin/sdat2img/sdat2img.py", line 55, in parse_transfer_list_file
    2021/12/16 09:04:22 CMD:0: trans_list = open(TRANSFER_LIST_FILE, 'r')
    2021/12/16 09:04:22 CMD:0: IOError: [Errno 2] No such file or directory: '/root/jancox/bin/flashable/vendor.transfer.list'
    2021-12-16 09:04:22.045 IsError ▶ ot/go/pkg/mod/github.com/kokizzu/[email protected]/goproc.go:301: github.com/kokizzu/goproc.(*Goproc).Start: CMD:0: error proc.exe.Wait /usr/bin/python "/root/jancox/bin/sdat2img/sdat2img.py" "/root/jancox/bin/flashable/vendor.transfer.list" "/root/jancox/bin/flashable/vendor.new.dat" "/root/jancox/bin/tmp/vendor.img"
    2021-12-16 09:04:22.046 IsError ▶ &exec.ExitError{
    ProcessState: &os.ProcessState{
    pid: 25204,
    status: 0x100,
    rusage: &syscall.Rusage{
    Utime: syscall.Timeval{Sec:0, Usec:75936},
    Stime: syscall.Timeval{Sec:0, Usec:44058},
    Maxrss: 6144,
    Ixrss: 0,
    Idrss: 0,
    Isrss: 0,
    Minflt: 901,
    Majflt: 0,
    Nswap: 0,
    Inblock: 0,
    Oublock: 0,
    Msgsnd: 0,
    Msgrcv: 0,
    Nsignals: 0,
    Nvcsw: 660,
    Nivcsw: 1,
    },
    },
    Stderr: nil,
    }
    2021-12-16 09:04:22.047 IsError ▶ &exec.ExitError{
    ProcessState: &os.ProcessState{
    pid: 25204,
    status: 0x100,
    rusage: &syscall.Rusage{
    Utime: syscall.Timeval{Sec:0, Usec:75936},
    Stime: syscall.Timeval{Sec:0, Usec:44058},
    Maxrss: 6144,
    Ixrss: 0,
    Idrss: 0,
    Isrss: 0,
    Minflt: 901,
    Majflt: 0,
    Nswap: 0,
    Inblock: 0,
    Oublock: 0,
    Msgsnd: 0,
    Msgrcv: 0,
    Nsignals: 0,
    Nvcsw: 660,
    Nivcsw: 1,
    },
    },
    Stderr: nil,
    }
    StackTrace:
    2021/12/16 09:04:22 CMD:0: max restart reached 0
    product
    2021/12/16 09:04:22 CMD:0: starting: /usr/bin/python "/root/jancox/bin/sdat2img/sdat2img.py" "/root/jancox/bin/flashable/product.transfer.list" "/root/jancox/bin/flashable/product.new.dat" "/root/jancox/bin/tmp/product.img"
    2021/12/16 09:04:22 CMD:0: sdat2img binary - version: 1.0
    2021/12/16 09:04:22 CMD:0:
    2021/12/16 09:04:22 CMD:0: Traceback (most recent call last):
    2021/12/16 09:04:22 CMD:0: File "/root/jancox/bin/sdat2img/sdat2img.py", line 142, in
    2021/12/16 09:04:22 CMD:0: main(sys.argv)
    2021/12/16 09:04:22 CMD:0: File "/root/jancox/bin/sdat2img/sdat2img.py", line 87, in main
    2021/12/16 09:04:22 CMD:0: version, new_blocks, commands = parse_transfer_list_file(TRANSFER_LIST_FILE)
    2021/12/16 09:04:22 CMD:0: File "/root/jancox/bin/sdat2img/sdat2img.py", line 55, in parse_transfer_list_file
    2021/12/16 09:04:22 CMD:0: trans_list = open(TRANSFER_LIST_FILE, 'r')
    2021/12/16 09:04:22 CMD:0: IOError: [Errno 2] No such file or directory: '/root/jancox/bin/flashable/product.transfer.list'
    2021-12-16 09:04:22.249 IsError ▶ ot/go/pkg/mod/github.com/kokizzu/[email protected]/goproc.go:301: github.com/kokizzu/goproc.(*Goproc).Start: CMD:0: error proc.exe.Wait /usr/bin/python "/root/jancox/bin/sdat2img/sdat2img.py" "/root/jancox/bin/flashable/product.transfer.list" "/root/jancox/bin/flashable/product.new.dat" "/root/jancox/bin/tmp/product.img"
    2021-12-16 09:04:22.249 IsError ▶ &exec.ExitError{
    ProcessState: &os.ProcessState{
    pid: 25205,
    status: 0x100,
    rusage: &syscall.Rusage{
    Utime: syscall.Timeval{Sec:0, Usec:62051},
    Stime: syscall.Timeval{Sec:0, Usec:44564},
    Maxrss: 6152,
    Ixrss: 0,
    Idrss: 0,
    Isrss: 0,
    Minflt: 901,
    Majflt: 0,
    Nswap: 0,
    Inblock: 0,
    Oublock: 0,
    Msgsnd: 0,
    Msgrcv: 0,
    Nsignals: 0,
    Nvcsw: 660,
    Nivcsw: 9,
    },
    },
    Stderr: nil,
    }
    2021-12-16 09:04:22.250 IsError ▶ &exec.ExitError{
    ProcessState: &os.ProcessState{
    pid: 25205,
    status: 0x100,
    rusage: &syscall.Rusage{
    Utime: syscall.Timeval{Sec:0, Usec:62051},
    Stime: syscall.Timeval{Sec:0, Usec:44564},
    Maxrss: 6152,
    Ixrss: 0,
    Idrss: 0,
    Isrss: 0,
    Minflt: 901,
    Majflt: 0,
    Nswap: 0,
    Inblock: 0,
    Oublock: 0,
    Msgsnd: 0,
    Msgrcv: 0,
    Nsignals: 0,
    Nvcsw: 660,
    Nivcsw: 9,
    },
    },
    Stderr: nil,
    }
    StackTrace:
    2021/12/16 09:04:22 CMD:0: max restart reached 0
    system_ext
    2021/12/16 09:04:22 CMD:0: starting: /usr/bin/python "/root/jancox/bin/sdat2img/sdat2img.py" "/root/jancox/bin/flashable/system_ext.transfer.list" "/root/jancox/bin/flashable/system_ext.new.dat" "/root/jancox/bin/tmp/system_ext.img"
    2021/12/16 09:04:22 CMD:0: sdat2img binary - version: 1.0
    2021/12/16 09:04:22 CMD:0:
    2021/12/16 09:04:22 CMD:0: Android Nougat 7.x / Oreo 8.x detected!
    2021/12/16 09:04:22 CMD:0:
    2021/12/16 09:04:22 CMD:0: Traceback (most recent call last):
    2021/12/16 09:04:22 CMD:0: File "/root/jancox/bin/sdat2img/sdat2img.py", line 142, in
    2021/12/16 09:04:22 CMD:0: main(sys.argv)
    2021/12/16 09:04:22 CMD:0: File "/root/jancox/bin/sdat2img/sdat2img.py", line 111, in main
    2021/12/16 09:04:22 CMD:0: new_data_file = open(NEW_DATA_FILE, 'rb')
    2021/12/16 09:04:22 CMD:0: IOError: [Errno 21] Is a directory: '/root/jancox/bin/flashable/system_ext.new.dat'
    2021-12-16 09:04:22.496 IsError ▶ ot/go/pkg/mod/github.com/kokizzu/[email protected]/goproc.go:301: github.com/kokizzu/goproc.(*Goproc).Start: CMD:0: error proc.exe.Wait /usr/bin/python "/root/jancox/bin/sdat2img/sdat2img.py" "/root/jancox/bin/flashable/system_ext.transfer.list" "/root/jancox/bin/flashable/system_ext.new.dat" "/root/jancox/bin/tmp/system_ext.img"
    2021-12-16 09:04:22.496 IsError ▶ &exec.ExitError{
    ProcessState: &os.ProcessState{
    pid: 25206,
    status: 0x100,
    rusage: &syscall.Rusage{
    Utime: syscall.Timeval{Sec:0, Usec:69425},
    Stime: syscall.Timeval{Sec:0, Usec:52084},
    Maxrss: 6220,
    Ixrss: 0,
    Idrss: 0,
    Isrss: 0,
    Minflt: 904,
    Majflt: 1,
    Nswap: 0,
    Inblock: 232,
    Oublock: 8,
    Msgsnd: 0,
    Msgrcv: 0,
    Nsignals: 0,
    Nvcsw: 669,
    Nivcsw: 4,
    },
    },
    Stderr: nil,
    }
    2021-12-16 09:04:22.497 IsError ▶ &exec.ExitError{
    ProcessState: &os.ProcessState{
    pid: 25206,
    status: 0x100,
    rusage: &syscall.Rusage{
    Utime: syscall.Timeval{Sec:0, Usec:69425},
    Stime: syscall.Timeval{Sec:0, Usec:52084},
    Maxrss: 6220,
    Ixrss: 0,
    Idrss: 0,
    Isrss: 0,
    Minflt: 904,
    Majflt: 1,
    Nswap: 0,
    Inblock: 232,
    Oublock: 8,
    Msgsnd: 0,
    Msgrcv: 0,
    Nsignals: 0,
    Nvcsw: 669,
    Nivcsw: 4,
    },
    },
    Stderr: nil,
    }
    StackTrace:
    2021/12/16 09:04:22 CMD:0: max restart reached 0
    root@localhost:~/jancox#

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.