How do I get my Golang web server to run in the background?
Simple / Usable things first
If you want a start script without much effort (i.e. dealing with the process, just having it managed by the system), you could create a systemd
service. See Greg's answer for a detailled description on how to do that.
Afterwards you can start the service with
systemctl start myserver
Previously I would have recommended trying xinetd
or something similar for finer granuarlity regarding resource and permission management but systemd already covers that.
Using the shell
You could start your process like this:
nohup ./myexecutable &
The &
tells the shell to start the command in the background, keeping it in the job list.
On some shells, the job is killed if the parent shell exits using the HANGUP signal.
To prevent this, you can launch your command using the nohup
command, which discards the HANGUP signal.
However, this does not work, if the called process reconnects the HANGUP signal.
To be really sure, you need to remove the process from the shell's joblist.
For two well known shells this can be achieved as follows:
bash:
./myexecutable &
disown <pid>
zsh:
./myexecutable &!
Killing your background job
Normally, the shell prints the PID of the process, which then can be killed using the kill
command, to stop the server. If your shell does not print the PID, you can get it using
echo $!
directly after execution. This prints the PID of the forked process.
Keep running Go Server as background process
We have to inspect an always-on server from 2 perspectives:
- Handle / tolerate errors that occur during serving requests
- Restart the server app if it crashes or gets killed
For the first, you don't have to do anything special. If your handler panics, it will not blow your whole server, the http server will recover from that. It will only stop serving that specific request. Of course you can create your own handler which calls other handlers and recovers on panic and handle it in an intelligent way, but this is not a requirement.
One thing to note here: a Go app ends when the main
goroutine ends (that is: the main()
function returns). So even though goroutines serving requests are protected, if your main goroutine would end (e.g.
panic), your app would still exit.
For the second, it's not really Go related. For example if you're on linux, simply install / register your compiled Go executable as a service, properly configured to have it restarted should it exit or crash.
For example in Ubuntu which uses systemd for service configuration, the following minimal service descriptor would fulfill your wishes:
[Unit]
Description=My Always-on Service
[Service]
Restart=always
Type=simple
ExecStart=/path/to/your/app -some=params passed
[Install]
WantedBy=multi-user.target
Put the above text in a file e.g. /etc/systemd/system/myservice.service
, and you can enable and start it with:
sudo systemctl enable myservice.service
sudo systemctl start myservice.service
The first command places a symlink to the proper folder to have it auto-started on system startup. The second command starts it right now.
To verify if it's running, type:
sudo systemctl status myservice.service
(You can omit the .service
extension in most cases.)
Now whenever your app crashes, or the OS gets restarted, your app will be automatically started / restarted.
Further reading and tutorials for systemd:
How To Use Systemctl to Manage Systemd Services and Units
Systemd Essentials: Working with Services, Units, and the Journal
Convert "run at startup" script from upstart to systemd for Ubuntu 16
systemd: Writing and Enabling a Service
Can i run a golang application as a background process? ( without nohup)
For those who are interested. i solved this using the github.com/kardianos/service package. It worked by installing the application as a service and I can start or stop it from the command line without blocking. Tested out and it worked on both Linux and Windows, which served my purpose.
Sample code will me like such :-
package main
import (
"flag"
"fmt"
"log"
"net/http"
"github.com/kardianos/service"
)
var logger service.Logger
// Program structures.
// Define Start and Stop methods.
type program struct {
exit chan struct{}
}
func (p *program) Start(s service.Service) error {
if service.Interactive() {
logger.Info("Running in terminal.")
} else {
logger.Info("Running under service manager.")
}
p.exit = make(chan struct{})
// Start should not block. Do the actual work async.
go p.run()
return nil
}
func (p *program) run() error {
logger.Infof("I'm running %v.", service.Platform())
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
return nil
}
func (p *program) Stop(s service.Service) error {
// Any work in Stop should be quick, usually a few seconds at most.
logger.Info("I'm Stopping!")
close(p.exit)
return nil
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}
func main() {
svcFlag := flag.String("service", "", "Control the system service.")
flag.Parse()
options := make(service.KeyValue)
options["Restart"] = "on-success"
options["SuccessExitStatus"] = "1 2 8 SIGKILL"
svcConfig := &service.Config{
Name: "GoExample",
DisplayName: "Go Example",
Description: "This is a Go application.",
Dependencies: []string{},
// "Requires=network.target",
// "After=network-online.target syslog.target"
Option: options,
}
prg := &program{}
s, err := service.New(prg, svcConfig)
if err != nil {
log.Fatal(err)
}
errs := make(chan error, 5)
logger, err = s.Logger(errs)
if err != nil {
log.Fatal(err)
}
go func() {
for {
err := <-errs
if err != nil {
log.Print(err)
}
}
}()
if len(*svcFlag) != 0 {
err := service.Control(s, *svcFlag)
if err != nil {
log.Printf("Valid actions: %q\n", service.ControlAction)
log.Fatal(err)
}
return
}
err = s.Run()
if err != nil {
logger.Error(err)
}
}
go run app.go always run in the background
Did you tried running your server using nohup?
nohup go run server.go &
How I should run my Golang process in background?
As Nick mentioned Supervisord is a great option that has also worked well in my experience.
Nick mentioned problems with forking- forking itself works fine AFAICT. The issue is not forking but dropping privileges. Due to the way the Go runtime starts the thread pool that goroutines are multiplexed over (when GOMAXPROX > 1), the setuid systemcall is not a reliable way to drop permissions.
Instead, you should run your program as a non-privileged user and use the setcap utility to grant it the needed permissions.
For example, to allow binding to a low port number (like 80) run will need to run setcap once on the executable: sudo setcap 'cap_net_bind_service=+ep' /opt/yourGoBinary
You may need to install setcap: sudo aptitude install libcap2-bin
What's the best practices to run a background task along with server listening
Yes, and remember that main
is a goroutine too, here is the working code:
package main
import (
"fmt"
"net/http"
"time"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}
func checkExpire() {
for {
// do some job
fmt.Println(time.Now().UTC())
time.Sleep(1000 * time.Millisecond)
}
}
func main() {
go checkExpire()
http.HandleFunc("/", handler) // http://127.0.0.1:8080/Go
http.ListenAndServe(":8080", nil)
}
Run the code and open your browser.
And never use Empty loop (for{}
) see:
Difference between the main goroutine and spawned goroutines of a Go program
Empty loop uses 100% of a CPU Core, to wait for some operation depending to the use case you may use:
- sync.WaitGroup
like this
- select {}
like this
- channels
- time.Sleep
How can i run my Web application in background?
you can use a curl command and run it in background using nohup on a unix machine
like
nohup curl https://xxxxxx &
you need to explore a bit more how you ll make the same request using curl which are you making using the browser
this will run it in background even if you shut your shell terminal until your unix server is running
Long running tasks in a web server
No: a goroutine can last as long as you want (and the main program): you only need to know, as mentioned here, when to terminate said goroutine.
In your case, you would have to detect your connection has been terminated by the user, as in "Close the goroutine reading from a TCP connection without closing connection".
Related Topics
Best Way to Set Environment Variables in Calling Shell
How to Use Stdin Twice from Pipe
Qt Creator: Add Qt Module to Project
Ftdi D2Xx Conflict with Ftdi_Sio on Linux - How to Remove Ftdi_Sio Automatically
How to Disable CPU Cache (L1/L2) on a Linux System
Should %Rsp Be Aligned to 16-Byte Boundary Before Calling a Function in Nasm
Using a Glob Expression Passed as a Bash Script Argument
Android Studio 3.0 Emulator Does Not Start
Linux:How to Set Default Route from C
Suppress Notice of Forked Command Being Killed
Why Is Gdb Breakpoint Set at the Wrong Address for an X86 Assembly Function
How to Insert Ctrl+D into My Linux Script
Linux Task Schedule to Hour, Minute, Second
Change Default Names for Usb Virtual Serial Ports in Linux
Undefined Reference to 'Dlopen'
How to Force Linking with a Static Library When a Shared Library of Same Name Is Present