get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/server/service_windows.go (about) 1 // Copyright 2012-2019 The NATS Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package server 15 16 import ( 17 "os" 18 "time" 19 20 "golang.org/x/sys/windows/svc" 21 ) 22 23 const ( 24 reopenLogCode = 128 25 reopenLogCmd = svc.Cmd(reopenLogCode) 26 ldmCode = 129 27 ldmCmd = svc.Cmd(ldmCode) 28 acceptReopenLog = svc.Accepted(reopenLogCode) 29 ) 30 31 var serviceName = "nats-server" 32 33 // SetServiceName allows setting a different service name 34 func SetServiceName(name string) { 35 serviceName = name 36 } 37 38 // winServiceWrapper implements the svc.Handler interface for implementing 39 // nats-server as a Windows service. 40 type winServiceWrapper struct { 41 server *Server 42 } 43 44 var dockerized = false 45 var startupDelay = 10 * time.Second 46 47 func init() { 48 if v, exists := os.LookupEnv("NATS_DOCKERIZED"); exists && v == "1" { 49 dockerized = true 50 } 51 } 52 53 // Execute will be called by the package code at the start of 54 // the service, and the service will exit once Execute completes. 55 // Inside Execute you must read service change requests from r and 56 // act accordingly. You must keep service control manager up to date 57 // about state of your service by writing into s as required. 58 // args contains service name followed by argument strings passed 59 // to the service. 60 // You can provide service exit code in exitCode return parameter, 61 // with 0 being "no error". You can also indicate if exit code, 62 // if any, is service specific or not by using svcSpecificEC 63 // parameter. 64 func (w *winServiceWrapper) Execute(args []string, changes <-chan svc.ChangeRequest, 65 status chan<- svc.Status) (bool, uint32) { 66 67 status <- svc.Status{State: svc.StartPending} 68 go w.server.Start() 69 70 if v, exists := os.LookupEnv("NATS_STARTUP_DELAY"); exists { 71 if delay, err := time.ParseDuration(v); err == nil { 72 startupDelay = delay 73 } else { 74 w.server.Errorf("Failed to parse \"%v\" as a duration for startup: %s", v, err) 75 } 76 } 77 // Wait for accept loop(s) to be started 78 if !w.server.ReadyForConnections(startupDelay) { 79 // Failed to start. 80 return false, 1 81 } 82 83 status <- svc.Status{ 84 State: svc.Running, 85 Accepts: svc.AcceptStop | svc.AcceptShutdown | svc.AcceptParamChange | acceptReopenLog, 86 } 87 88 loop: 89 for change := range changes { 90 switch change.Cmd { 91 case svc.Interrogate: 92 status <- change.CurrentStatus 93 case svc.Stop, svc.Shutdown: 94 w.server.Shutdown() 95 break loop 96 case reopenLogCmd: 97 // File log re-open for rotating file logs. 98 w.server.ReOpenLogFile() 99 case ldmCmd: 100 go w.server.lameDuckMode() 101 case svc.ParamChange: 102 if err := w.server.Reload(); err != nil { 103 w.server.Errorf("Failed to reload server configuration: %s", err) 104 } 105 default: 106 w.server.Debugf("Unexpected control request: %v", change.Cmd) 107 } 108 } 109 110 status <- svc.Status{State: svc.StopPending} 111 return false, 0 112 } 113 114 // Run starts the NATS server as a Windows service. 115 func Run(server *Server) error { 116 if dockerized { 117 server.Start() 118 return nil 119 } 120 isWindowsService, err := svc.IsWindowsService() 121 if err != nil { 122 return err 123 } 124 if !isWindowsService { 125 server.Start() 126 return nil 127 } 128 return svc.Run(serviceName, &winServiceWrapper{server}) 129 } 130 131 // isWindowsService indicates if NATS is running as a Windows service. 132 func isWindowsService() bool { 133 if dockerized { 134 return false 135 } 136 isWindowsService, _ := svc.IsWindowsService() 137 return isWindowsService 138 }