-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
runtime: support for daemonize #227
Comments
Unfortunately, this is a bit harder than it looks. On most systems, threads and daemonize do not play well with each other. Owner changed to r...@golang.org. Status changed to LongTerm. |
Comment 2 by azummo-google@towertech.it: I'm sure it is! Here (linux/386) I'm trying daemonizing early in main() and launching goroutine safterwards. Seems working nicely. |
While it might be useful to have a Fork() function for other purposes, I'd suggest omitting and discouraging any sort of Daemon()-like feature. It's usually a mistake for a daemon to fork itself. Self-daemonizing makes life unnecessarily hard for anyone who wants to monitor the daemon process. |
I've run into a number of cases where, say, a given Linux distribution doesn't provide a useful/secure/correct daemonization wrapper utility, if any at all. In this case, self-daemonization, which is the defacto method, is assumed (and a good self-daemonizing program will have an option to leave a pidfile and logfiles, which will make it easy to monitor the process). Since daemonization really only occurs in the wild during initialization, it really ought to be called from an init function. In order to make fork safe for daemonization, and seeing that the spec has now changed (goroutines now *can* run during initialization), all we need to do is any one of three things: 1) Disallow creation of os threads during initialization, where go's concurrency support is only for concurrency, not parallelization, as Rob Pike might say -- all goroutine switching during init would probably need to be cooperative (through blocking or runtime.Gosched), which may not be possible to accomplish in the current runtime. 2) Create something like a runtime.SuspendAll() function, upon returning, guarantees that all other threads are muxed off of os threads (which are destroyed) and the calling goroutine is run alone until a complimentary function, like a runtime.ResumeAll() is called. This is not the same as GOMAXPROCS, which doesn't restrict the number of threads used by the runtime (this option would need to account for those as well). 3) Amend the published spec to require that unrelated dependencies initialize in code-order (this would also mean that gofmt wouldn't be allowed to reorder imports), or at least that independent import groups occur in source order. So at the minimum, the following should require that daemon initialize fully before threadspawner: import "daemon" // daemon imports nothing import ( "fmt" "os" "threadspawner" // threadspawner imports nothing ) (Binaries produced from 6g and friends appear to do this in either undefined or reverse order). Knowing nothing about the toolchain/runtime internals, #3 is probably the simplest to implement -- if you want to argue that the compiler be allowed to optimize for speed (putting goroutines-spawning initializers before non-concurrent initializers), keep in mind that initialization is not a critical place for speed (in a long running program, initialization time counts for nothing, and in short running programs, heavy lifting is usually *not* done in initialization). |
Comment 14 by cw@f00f.org: We can make daemonize work 'as expected' with a few restrictions. These restrictions won't apply to most people and almost never if called in or near program start-up. These restrictions aren't unique to Go, but we can detect and error on them rather than silently ignore them (as is sometimes the case elsewhere). |
Special casing a standard daemon package actually sounds like the most intuitive thing -- thanks Russ! In any case, programmers who roll their own almost always do the wrong thing (I think even the C daemon call doesn't handle it even close to securely), and we shouldn't make them worry about implementation details. |
Special casing a standard daemon package actually sounds like the most intuitive thing -- thanks Russ! In any case, programmers who roll their own almost always do the wrong thing (I think even the C daemon call doesn't handle it even close to securely), and we shouldn't make them worry about implementation details. |
Would your changes allow one to have multiple processes accepting socket connections for single listening socket like C does*? basically: proc1: sock.listen proc1: fork N children procN: s = sock.accept procN: do work on s * on Linux this is possible not sure about other OSes |
Comment 23 by cw@f00f.org: Or you could use SCM_RIGHTS after the fact. |
You can already detach from the controlling terminal by using StartProcess and setting stdin,stdout, and stderr to nil (Only tested on ubuntu 12.04 bash in a gnome-terminal). However we would still need a fork() approach if you wanted to drop privileges before detaching. Rory McGuire Email: rjmcguire@gmail.com Mobile: (+27)(0) 82 856 3646 |
Comment 29 by sergey.yarmonov: You can try package https://github.com/sevlyar/go-daemon |
Fixes golang/go#227 golang/go#219 Change-Id: Iafd4173bee475b823065c8d39d094f17a87a2671
I found those daemon packages that have emerged too complicated, here is my solution:
|
Your race-avoidance code still forms a race condition |
This should eliminate the race condition. Instead of the sleep, do:
|
Yeah, I think it's time we finally closed this. The answer is init systems like systemd, launchd, daemontools, supervisor, runit, Kubernetes, heroku, Borg, etc etc. |
Don't always need systemd, launchd, daemontools, supervisor, runit, Kubernetes, heroku, Borg, etc etc. when you have the shell's & operator. |
by azummo-google@towertech.it:
The text was updated successfully, but these errors were encountered: