Golang register as windows service

source code from https://github.com/bosun-monitor/bosun/blob/master/cmd/scollector/service_windows.go

package main

import (
	"flag"
	"fmt"
	"os"
	"time"

	"bosun.org/_version"
	"bosun.org/slog"
	"golang.org/x/sys/windows/svc"
	"golang.org/x/sys/windows/svc/debug"
	"golang.org/x/sys/windows/svc/eventlog"
	"golang.org/x/sys/windows/svc/mgr"
)

var win_service_command = flag.String("winsvc", "", "For Windows Service, can be install, remove, start, stop")

var serviceRunning = false

func init() {
	mains = append(mains, win_service_main)
}

func win_service_main() {
	const svcName = "scollector"
	var err error
	switch *win_service_command {
	case "install":
		err = installService(svcName, "Stack Exchange's Metric Collection Agent")
	case "remove":
		err = removeService(svcName)
	case "start":
		err = startService(svcName)
	case "stop":
		err = controlService(svcName, svc.Stop, svc.Stopped)
	case "":
		isIntSess, err := svc.IsAnInteractiveSession()
		if err != nil {
			slog.Fatalf("failed to determine if we are running in an interactive session: %v", err)
		}
		if !isIntSess {
			go runService(svcName, false)
			for {
				//Need to wait for service go routine to finish initializing. Otherwise the collector goroutines could
				//use all the CPU and cause Windows Service API to bail with a service unresponsive on startup error.
				//If service doesn't start within 30 seconds then the Windows Service API will kill the process.
				time.Sleep(time.Millisecond * 200)
				if serviceRunning {
					break
				}
			}
		}
		return
	default:
		slog.Fatalf("unknown winsvc command: %v", *win_service_command)
	}
	if err != nil {
		slog.Fatalf("failed to %s %s: %v", *win_service_command, svcName, err)
	}
	os.Exit(0)
}

func installService(name, desc string) error {
	exepath, err := exePath()
	if err != nil {
		return err
	}
	m, err := mgr.Connect()
	if err != nil {
		return err
	}
	defer m.Disconnect()
	s, err := m.OpenService(name)
	if err == nil {
		s.Close()
		return fmt.Errorf("service %s already exists", name)
	}
	s, err = m.CreateService(name, exepath, mgr.Config{DisplayName: name,
		StartType:   mgr.StartAutomatic,
		Description: desc})
	if err != nil {
		return err
	}
	defer s.Close()
	err = eventlog.InstallAsEventCreate(name, eventlog.Error|eventlog.Warning|eventlog.Info)
	if err != nil {
		s.Delete()
		return fmt.Errorf("SetupEventLogSource() failed: %s", err)
	}
	return nil
}

func removeService(name string) error {
	m, err := mgr.Connect()
	if err != nil {
		return err
	}
	defer m.Disconnect()
	s, err := m.OpenService(name)
	if err != nil {
		return fmt.Errorf("service %s is not installed", name)
	}
	defer s.Close()
	err = s.Delete()
	if err != nil {
		return err
	}
	err = eventlog.Remove(name)
	if err != nil {
		return fmt.Errorf("RemoveEventLogSource() failed: %s", err)
	}
	return nil
}

func startService(name string) error {
	m, err := mgr.Connect()
	if err != nil {
		return err
	}
	defer m.Disconnect()
	s, err := m.OpenService(name)
	if err != nil {
		return fmt.Errorf("could not access service: %v", err)
	}
	defer s.Close()
	err = s.Start()
	if err != nil {
		return fmt.Errorf("could not start service: %v", err)
	}
	return nil
}

func controlService(name string, c svc.Cmd, to svc.State) error {
	m, err := mgr.Connect()
	if err != nil {
		return err
	}
	defer m.Disconnect()
	s, err := m.OpenService(name)
	if err != nil {
		return fmt.Errorf("could not access service: %v", err)
	}
	defer s.Close()
	status, err := s.Control(c)
	if err != nil {
		return fmt.Errorf("could not send control=%d: %v", c, err)
	}
	timeout := time.Now().Add(35 * time.Second)
	for status.State != to {
		if timeout.Before(time.Now()) {
			return fmt.Errorf("timeout waiting for service to go to state=%d", to)
		}
		time.Sleep(300 * time.Millisecond)
		status, err = s.Query()
		if err != nil {
			return fmt.Errorf("could not retrieve service status: %v", err)
		}
	}
	return nil
}

type s struct{}

func (m *s) Execute(args []string, r 

Post: 2017-03-23 07:54:22

Views: 1

Follow me: @twitter @github
Scan QR code and Donate me via alipay:
donate me via alipay
Donate me Bitcoin:136MYemy5QmmBPLBLr1GHZfkES7CsoG4Qh
Powered by GoSense RSS