1

Is it possible to run a golang application as a background process at the code level, without using nohup?

There is an example i found in the following link :- https://socketloop.com/tutorials/golang-daemonizing-a-simple-web-server-process-example

and it works, but it feels somehow hackish... Does anybody know a way that i can do the same without spawning a new process?

Thanks

Chirrut Imwe
  • 633
  • 10
  • 20
  • You cannot fork a go (or any other multi-threaded) process. You need to use a modern init system, or other controlling process to handle this for you. – JimB Jun 25 '20 at 17:57

3 Answers3

5

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)
    }

}
Chirrut Imwe
  • 633
  • 10
  • 20
4

There are packages like go-daemon to do this, but your program will be hard to run on non-POSIX systems.

If you target multiple platforms I recommend you to write your application to not daemonize itself and leave that task to whatever system service manager like systemd, daemontools, supervisord or whatever Mac OS X or Windows uses.

blami
  • 6,588
  • 2
  • 23
  • 31
2

You can use & and disown

example :

path/to/program& more info

disown more info

after that you can close your ssh or terminal.

to see program is running you can use ps aux

also see Difference between nohup, disown and &

ttrasn
  • 4,322
  • 4
  • 26
  • 43