I have a program which, in some cases, runs under Windows Services / Launchd / Systemd, and in other cases, is launched by a supervisor program I control. When using the supervisor program, I need a way to signal to the "service" when I want it to quit. On Linux, I can use signals, but on Windows, this is not supported, so I am using an RPC call. The problem is that I can't find a way to actually get the program to terminate besides calling os.Exit() which will not necessarily clean up all resources correctly.
I found this example which looked like you could manually call Stop from within the process: https://github.com/kardianos/service/blob/master/example/runner/runner.go#L60-L66
But when I actually tried this, the program does not exit. PoC below:
package main
import (
"fmt"
"log"
"time"
"github.com/kardianos/service"
)
var logger service.Logger
type program struct{}
func (p *program) Start(s service.Service) error {
fmt.Println("Service starting...")
go p.run(s)
return nil
}
func (p *program) run(s service.Service) {
fmt.Println("Running work function...")
fmt.Println("Work completed. This function has returned.")
// Note: Even though this function returns, the program won't exit when run interactively
p.Stop(s)
}
func (p *program) Stop(s service.Service) error {
fmt.Println("Service stopping...")
// Stop should not block. Return within a few seconds.
return nil
}
func main() {
svcConfig := &service.Config{
Name: "GoServiceExampleSimple",
DisplayName: "Go Service Example",
Description: "This is an example Go service.",
}
prg := &program{}
s, err := service.New(prg, svcConfig)
if err != nil {
log.Fatal(err)
}
logger, err = s.Logger(nil)
if err != nil {
log.Fatal(err)
}
// Check if running interactively using the proper API
isInteractive := service.Interactive()
if isInteractive {
fmt.Println("Running in interactive mode")
fmt.Println("Notice: This program will NOT exit automatically after work completes")
fmt.Println("Press Ctrl+C to exit manually")
}
// Add a timestamp to show when execution starts
fmt.Printf("Program started at: %s\n", time.Now().Format(time.RFC3339))
err = s.Run()
if err != nil {
logger.Error(err)
}
// This line will never be reached when running interactively
fmt.Println("Program exited normally")
}
I believe it's due to waiting on this signal, which I can't trigger or access the channel of to manually close:
|
sigChan := make(chan os.Signal) |
|
|
|
signal.Notify(sigChan, os.Interrupt) |
|
|
|
<-sigChan |
Or on macOS:
|
var sigChan = make(chan os.Signal, 3) |
|
signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt) |
|
<-sigChan |
I have a program which, in some cases, runs under Windows Services / Launchd / Systemd, and in other cases, is launched by a supervisor program I control. When using the supervisor program, I need a way to signal to the "service" when I want it to quit. On Linux, I can use signals, but on Windows, this is not supported, so I am using an RPC call. The problem is that I can't find a way to actually get the program to terminate besides calling
os.Exit()which will not necessarily clean up all resources correctly.I found this example which looked like you could manually call Stop from within the process: https://github.com/kardianos/service/blob/master/example/runner/runner.go#L60-L66
But when I actually tried this, the program does not exit. PoC below:
I believe it's due to waiting on this signal, which I can't trigger or access the channel of to manually close:
service/service_windows.go
Lines 397 to 401 in becf2eb
Or on macOS:
service/service_darwin.go
Lines 274 to 276 in becf2eb