A daemon package for use with Go (golang) services
package main
import (
"fmt""log""github.com/takama/daemon"
)
funcmain() {
service, err:=daemon.New("name", "description", daemon.SystemDaemon)
iferr!=nil {
log.Fatal("Error: ", err)
}
status, err:=service.Install()
iferr!=nil {
log.Fatal(status, "\nError: ", err)
}
fmt.Println(status)
}// Example of a daemon with echo servicepackage main
import (
"fmt""log""net""os""os/signal""syscall""github.com/takama/daemon"
)
const (
// name of the servicename="myservice"description="My Echo Service"// port which daemon should be listenport=":9977"
)
// dependencies that are NOT required by the service, but might be usedvardependencies= []string{"dummy.service"}
varstdlog, errlog*log.Logger// Service has embedded daemontypeServicestruct {
daemon.Daemon
}
// Manage by daemon commands or run the daemonfunc (service*Service) Manage() (string, error) {
usage:="Usage: myservice install | remove | start | stop | status"// if received any kind of command, do itiflen(os.Args) >1 {
command:=os.Args[1]
switchcommand {
case"install":
returnservice.Install()
case"remove":
returnservice.Remove()
case"start":
returnservice.Start()
case"stop":
returnservice.Stop()
case"status":
returnservice.Status()
default:
returnusage, nil
}
}
// Do something, call your goroutines, etc// Set up channel on which to send signal notifications.// We must use a buffered channel or risk missing the signal// if we're not ready to receive when the signal is sent.interrupt:=make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)
// Set up listener for defined host and portlistener, err:=net.Listen("tcp", port)
iferr!=nil {
return"Possibly was a problem with the port binding", err
}
// set up channel on which to send accepted connectionslisten:=make(chan net.Conn, 100)
goacceptConnection(listener, listen)
// loop work cycle with accept connections or interrupt// by system signalfor {
select {
caseconn:=<-listen:
gohandleClient(conn)
casekillSignal:=<-interrupt:
stdlog.Println("Got signal:", killSignal)
stdlog.Println("Stoping listening on ", listener.Addr())
listener.Close()
ifkillSignal==os.Interrupt {
return"Daemon was interruped by system signal", nil
}
return"Daemon was killed", nil
}
}
// never happen, but need to complete codereturnusage, nil
}
// Accept a client connection and collect it in a channelfuncacceptConnection(listener net.Listener, listenchan<- net.Conn) {
for {
conn, err:=listener.Accept()
iferr!=nil {
continue
}
listen<-conn
}
}
funchandleClient(client net.Conn) {
for {
buf:=make([]byte, 4096)
numbytes, err:=client.Read(buf)
ifnumbytes==0||err!=nil {
return
}
client.Write(buf[:numbytes])
}
}
funcinit() {
stdlog=log.New(os.Stdout, "", log.Ldate|log.Ltime)
errlog=log.New(os.Stderr, "", log.Ldate|log.Ltime)
}
funcmain() {
srv, err:=daemon.New(name, description, daemon.SystemDaemon, dependencies...)
iferr!=nil {
errlog.Println("Error: ", err)
os.Exit(1)
}
service:=&Service{srv}
status, err:=service.Manage()
iferr!=nil {
errlog.Println(status, "\nError: ", err)
os.Exit(1)
}
fmt.Println(status)
}Optionally, service config file can be retrieved or updated by calling
GetTemplate() string and SetTemplate(string) methods(except MS
Windows). Template will be a default Go Template("text/template").
If SetTemplate is not called, default template content will be used
while creating service.
| Variable | Description |
|---|---|
| Description | Description for service |
| Dependencies | Service dependencies |
| Name | Service name |
| Path | Path of service executable |
| Args | Arguments for service executable |
[Unit]Description={{.Description}}
Requires={{.Dependencies}}
After={{.Dependencies}}
[Service]PIDFile=/var/run/{{.Name}}.pid
ExecStartPre=/bin/rm -f /var/run/{{.Name}}.pid
ExecStart={{.Path}} {{.Args}}
Restart=on-failure
[Install]WantedBy=multi-user.targetSee examples/cron/cron_job.go
- Sheile
- Nguyen Trung Loi
- Donny Prasetyobudi
- Mark Berner
- Fatih Kaya
- Jannick Fahlbusch
- TobyZXJ
- Pichu Chen
- Eric Halpern
- Yota
- Erkan Durmus
- maxxant
- 1for
- okamura
- 0X8C - Demired
- Maximus
- AlgorathDev
- Alexis Camilleri
- neverland4u
- Rustam
- King'ori Maina
All the contributors are welcome. If you would like to be the contributor please accept some rules.
- The pull requests will be accepted only in
developbranch - All modifications or additions should be tested
- Sorry, We will not accept code with any dependency, only standard library
Thank you for your understanding!