get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/server/signal_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  	"fmt"
    18  	"os"
    19  	"os/signal"
    20  	"syscall"
    21  	"time"
    22  
    23  	"golang.org/x/sys/windows/svc"
    24  	"golang.org/x/sys/windows/svc/mgr"
    25  )
    26  
    27  // Signal Handling
    28  func (s *Server) handleSignals() {
    29  	if s.getOpts().NoSigs {
    30  		return
    31  	}
    32  	c := make(chan os.Signal, 1)
    33  
    34  	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
    35  
    36  	go func() {
    37  		for {
    38  			select {
    39  			case sig := <-c:
    40  				s.Debugf("Trapped %q signal", sig)
    41  				s.Shutdown()
    42  				os.Exit(0)
    43  			case <-s.quitCh:
    44  				return
    45  			}
    46  		}
    47  	}()
    48  }
    49  
    50  // ProcessSignal sends the given signal command to the running nats-server service.
    51  // If service is empty, this signals the "nats-server" service. This returns an
    52  // error is the given service is not running or the command is invalid.
    53  func ProcessSignal(command Command, service string) error {
    54  	if service == "" {
    55  		service = serviceName
    56  	}
    57  
    58  	m, err := mgr.Connect()
    59  	if err != nil {
    60  		return err
    61  	}
    62  	defer m.Disconnect()
    63  
    64  	s, err := m.OpenService(service)
    65  	if err != nil {
    66  		return fmt.Errorf("could not access service: %v", err)
    67  	}
    68  	defer s.Close()
    69  
    70  	var (
    71  		cmd svc.Cmd
    72  		to  svc.State
    73  	)
    74  
    75  	switch command {
    76  	case CommandStop, CommandQuit:
    77  		cmd = svc.Stop
    78  		to = svc.Stopped
    79  	case CommandReopen:
    80  		cmd = reopenLogCmd
    81  		to = svc.Running
    82  	case CommandReload:
    83  		cmd = svc.ParamChange
    84  		to = svc.Running
    85  	case commandLDMode:
    86  		cmd = ldmCmd
    87  		to = svc.Running
    88  	default:
    89  		return fmt.Errorf("unknown signal %q", command)
    90  	}
    91  
    92  	status, err := s.Control(cmd)
    93  	if err != nil {
    94  		return fmt.Errorf("could not send control=%d: %v", cmd, err)
    95  	}
    96  
    97  	timeout := time.Now().Add(10 * time.Second)
    98  	for status.State != to {
    99  		if timeout.Before(time.Now()) {
   100  			return fmt.Errorf("timeout waiting for service to go to state=%d", to)
   101  		}
   102  		time.Sleep(300 * time.Millisecond)
   103  		status, err = s.Query()
   104  		if err != nil {
   105  			return fmt.Errorf("could not retrieve service status: %v", err)
   106  		}
   107  	}
   108  
   109  	return nil
   110  }