gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/runtime/service.go (about)

     1  package runtime
     2  
     3  import (
     4  	"io"
     5  	"sync"
     6  	"time"
     7  
     8  	"gitee.com/liuxuezhan/go-micro-v1.18.0/runtime/build"
     9  
    10  	"gitee.com/liuxuezhan/go-micro-v1.18.0/runtime/process"
    11  	proc "gitee.com/liuxuezhan/go-micro-v1.18.0/runtime/process/os"
    12  	"gitee.com/liuxuezhan/go-micro-v1.18.0/util/log"
    13  )
    14  
    15  type service struct {
    16  	sync.RWMutex
    17  
    18  	running bool
    19  	closed  chan bool
    20  	err     error
    21  	updated time.Time
    22  
    23  	// output for logs
    24  	output io.Writer
    25  
    26  	// service to manage
    27  	*Service
    28  	// process creator
    29  	Process *proc.Process
    30  	// Exec
    31  	Exec *process.Executable
    32  	// process pid
    33  	PID *process.PID
    34  }
    35  
    36  func newService(s *Service, c CreateOptions) *service {
    37  	var exec string
    38  	var args []string
    39  
    40  	// set command
    41  	exec = c.Command[0]
    42  	// set args
    43  	if len(c.Command) > 1 {
    44  		args = c.Command[1:]
    45  	}
    46  
    47  	return &service{
    48  		Service: s,
    49  		Process: new(proc.Process),
    50  		Exec: &process.Executable{
    51  			Package: &build.Package{
    52  				Name: s.Name,
    53  				Path: exec,
    54  			},
    55  			Env:  c.Env,
    56  			Args: args,
    57  		},
    58  		closed:  make(chan bool),
    59  		output:  c.Output,
    60  		updated: time.Now(),
    61  	}
    62  }
    63  
    64  func (s *service) streamOutput() {
    65  	go io.Copy(s.output, s.PID.Output)
    66  	go io.Copy(s.output, s.PID.Error)
    67  }
    68  
    69  // Running returns true is the service is running
    70  func (s *service) Running() bool {
    71  	s.RLock()
    72  	defer s.RUnlock()
    73  	return s.running
    74  }
    75  
    76  // Start stars the service
    77  func (s *service) Start() error {
    78  	s.Lock()
    79  	defer s.Unlock()
    80  
    81  	if s.running {
    82  		return nil
    83  	}
    84  
    85  	// reset
    86  	s.err = nil
    87  	s.closed = make(chan bool)
    88  
    89  	// TODO: pull source & build binary
    90  	log.Debugf("Runtime service %s forking new process", s.Service.Name)
    91  	p, err := s.Process.Fork(s.Exec)
    92  	if err != nil {
    93  		return err
    94  	}
    95  
    96  	// set the pid
    97  	s.PID = p
    98  	// set to running
    99  	s.running = true
   100  
   101  	if s.output != nil {
   102  		s.streamOutput()
   103  	}
   104  
   105  	// wait and watch
   106  	go s.Wait()
   107  
   108  	return nil
   109  }
   110  
   111  // Stop stops the service
   112  func (s *service) Stop() error {
   113  	s.Lock()
   114  	defer s.Unlock()
   115  
   116  	select {
   117  	case <-s.closed:
   118  		return nil
   119  	default:
   120  		close(s.closed)
   121  		s.running = false
   122  		if s.PID == nil {
   123  			return nil
   124  		}
   125  		// kill the process
   126  		err := s.Process.Kill(s.PID)
   127  		// wait for it to exit
   128  		s.Process.Wait(s.PID)
   129  		// return the kill error
   130  		return err
   131  	}
   132  }
   133  
   134  // Error returns the last error service has returned
   135  func (s *service) Error() error {
   136  	s.RLock()
   137  	defer s.RUnlock()
   138  	return s.err
   139  }
   140  
   141  // Wait waits for the service to finish running
   142  func (s *service) Wait() {
   143  	// wait for process to exit
   144  	err := s.Process.Wait(s.PID)
   145  
   146  	s.Lock()
   147  	defer s.Unlock()
   148  
   149  	// save the error
   150  	if err != nil {
   151  		s.err = err
   152  	}
   153  
   154  	// no longer running
   155  	s.running = false
   156  }