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 }