Skip to content
forked from takama/daemon

A daemon package for use with Go (golang) services with no dependencies

License

Notifications You must be signed in to change notification settings

swiftdv8/daemon

 
 

Repository files navigation

Go Daemon

A daemon package for use with Go (golang) services with no dependencies

GoDoc

FORKED

Note: examples are not updated in line with code at this time.

The purpose of this fork is to provide flag and command pass through on services. This fork now provides that for linux distros and darwin (only tested on systemd). There is an issue stating that the takama devs not keen on breaking backward compatibility to implement part of this. However, I'm also not keen on maintaining a fork for such a minor deviation so this will hopefully be a temporary measure whilst I explore alternative approaches.

Further note: I'm not sure command pass-through is even possible on Windows services - I seem to remember having issues with this previously but possibly worked on win 10 (needs checking), either way it was not obvious how to pass this through on windows service init with current code

Examples

Simplest example (just install self as daemon)

package main

import (
    "fmt"
    "log"

    "github.com/takama/daemon"
)

func main() {
    service, err := daemon.New("name", "description")
    if err != nil {
        log.Fatal("Error: ", err)
    }
    status, err := service.Install()
    if err != nil {
        log.Fatal(status, "\nError: ", err)
    }
    fmt.Println(status)
}

Real example

// Example of a daemon with echo service
package main

import (
    "fmt"
    "log"
    "net"
    "os"
    "os/signal"
    "syscall"

    "github.com/takama/daemon"
)

const (

    // name of the service
    name        = "myservice"
    description = "My Echo Service"

    // port which daemon should be listen
    port = ":9977"
)

//    dependencies that are NOT required by the service, but might be used
var dependencies = []string{"dummy.service"}

var stdlog, errlog *log.Logger

// Service has embedded daemon
type Service struct {
    daemon.Daemon
}

// Manage by daemon commands or run the daemon
func (service *Service) Manage() (string, error) {

    usage := "Usage: myservice install | remove | start | stop | status"

    // if received any kind of command, do it
    if len(os.Args) > 1 {
        command := os.Args[1]
        switch command {
        case "install":
            return service.Install()
        case "remove":
            return service.Remove()
        case "start":
            return service.Start()
        case "stop":
            return service.Stop()
        case "status":
            return service.Status()
        default:
            return usage, 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 port
    listener, err := net.Listen("tcp", port)
    if err != nil {
        return "Possibly was a problem with the port binding", err
    }

    // set up channel on which to send accepted connections
    listen := make(chan net.Conn, 100)
    go acceptConnection(listener, listen)

    // loop work cycle with accept connections or interrupt
    // by system signal
    for {
        select {
        case conn := <-listen:
            go handleClient(conn)
        case killSignal := <-interrupt:
            stdlog.Println("Got signal:", killSignal)
            stdlog.Println("Stoping listening on ", listener.Addr())
            listener.Close()
            if killSignal == os.Interrupt {
                return "Daemon was interruped by system signal", nil
            }
            return "Daemon was killed", nil
        }
    }

    // never happen, but need to complete code
    return usage, nil
}

// Accept a client connection and collect it in a channel
func acceptConnection(listener net.Listener, listen chan<- net.Conn) {
    for {
        conn, err := listener.Accept()
        if err != nil {
            continue
        }
        listen <- conn
    }
}

func handleClient(client net.Conn) {
    for {
        buf := make([]byte, 4096)
        numbytes, err := client.Read(buf)
        if numbytes == 0 || err != nil {
            return
        }
        client.Write(buf[:numbytes])
    }
}

func init() {
    stdlog = log.New(os.Stdout, "", log.Ldate|log.Ltime)
    errlog = log.New(os.Stderr, "", log.Ldate|log.Ltime)
}

func main() {
    srv, err := daemon.New(name, description, dependencies...)
    if err != nil {
        errlog.Println("Error: ", err)
        os.Exit(1)
    }
    service := &Service{srv}
    status, err := service.Manage()
    if err != nil {
        errlog.Println(status, "\nError: ", err)
        os.Exit(1)
    }
    fmt.Println(status)
}

Cron example

See examples/cron/cron_job.go

Contributors (unsorted)

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 "develop" branch
  • All modifications or additions should be tested
  • Sorry, We will not accept code with any dependency, only standard library

Thank you for your understanding!

License

MIT Public License

About

A daemon package for use with Go (golang) services with no dependencies

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Go 100.0%