github.com/annwntech/go-micro/v2@v2.9.5/runtime/service/service.go (about) 1 package service 2 3 import ( 4 "context" 5 "sync" 6 7 "github.com/annwntech/go-micro/v2/client" 8 "github.com/annwntech/go-micro/v2/runtime" 9 pb "github.com/annwntech/go-micro/v2/runtime/service/proto" 10 ) 11 12 type svc struct { 13 sync.RWMutex 14 options runtime.Options 15 runtime pb.RuntimeService 16 } 17 18 // Init initializes runtime with given options 19 func (s *svc) Init(opts ...runtime.Option) error { 20 s.Lock() 21 defer s.Unlock() 22 23 for _, o := range opts { 24 o(&s.options) 25 } 26 27 // reset the runtime as the client could have changed 28 s.runtime = pb.NewRuntimeService(runtime.DefaultName, s.options.Client) 29 30 return nil 31 } 32 33 // Create registers a service in the runtime 34 func (s *svc) Create(svc *runtime.Service, opts ...runtime.CreateOption) error { 35 var options runtime.CreateOptions 36 for _, o := range opts { 37 o(&options) 38 } 39 if options.Context == nil { 40 options.Context = context.Background() 41 } 42 43 // set the default source from MICRO_RUNTIME_SOURCE 44 if len(svc.Source) == 0 { 45 svc.Source = s.options.Source 46 } 47 48 // runtime service create request 49 req := &pb.CreateRequest{ 50 Service: &pb.Service{ 51 Name: svc.Name, 52 Version: svc.Version, 53 Source: svc.Source, 54 Metadata: svc.Metadata, 55 }, 56 Options: &pb.CreateOptions{ 57 Command: options.Command, 58 Args: options.Args, 59 Env: options.Env, 60 Type: options.Type, 61 Image: options.Image, 62 }, 63 } 64 65 if _, err := s.runtime.Create(options.Context, req); err != nil { 66 return err 67 } 68 69 return nil 70 } 71 72 func (s *svc) Logs(service *runtime.Service, opts ...runtime.LogsOption) (runtime.LogStream, error) { 73 var options runtime.LogsOptions 74 for _, o := range opts { 75 o(&options) 76 } 77 78 if options.Context == nil { 79 options.Context = context.Background() 80 } 81 82 ls, err := s.runtime.Logs(options.Context, &pb.LogsRequest{ 83 Service: service.Name, 84 Stream: options.Stream, 85 Count: options.Count, 86 }) 87 if err != nil { 88 return nil, err 89 } 90 logStream := &serviceLogStream{ 91 service: service.Name, 92 stream: make(chan runtime.LogRecord), 93 stop: make(chan bool), 94 } 95 96 go func() { 97 for { 98 select { 99 // @todo this never seems to return, investigate 100 case <-ls.Context().Done(): 101 logStream.Stop() 102 } 103 } 104 }() 105 106 go func() { 107 for { 108 select { 109 // @todo this never seems to return, investigate 110 case <-ls.Context().Done(): 111 return 112 case _, ok := <-logStream.stream: 113 if !ok { 114 return 115 } 116 default: 117 record := pb.LogRecord{} 118 err := ls.RecvMsg(&record) 119 if err != nil { 120 logStream.Stop() 121 return 122 } 123 logStream.stream <- runtime.LogRecord{ 124 Message: record.GetMessage(), 125 Metadata: record.GetMetadata(), 126 } 127 } 128 } 129 }() 130 return logStream, nil 131 } 132 133 type serviceLogStream struct { 134 service string 135 stream chan runtime.LogRecord 136 sync.Mutex 137 stop chan bool 138 err error 139 } 140 141 func (l *serviceLogStream) Error() error { 142 return l.err 143 } 144 145 func (l *serviceLogStream) Chan() chan runtime.LogRecord { 146 return l.stream 147 } 148 149 func (l *serviceLogStream) Stop() error { 150 l.Lock() 151 defer l.Unlock() 152 select { 153 case <-l.stop: 154 return nil 155 default: 156 close(l.stream) 157 close(l.stop) 158 } 159 return nil 160 } 161 162 // Read returns the service with the given name from the runtime 163 func (s *svc) Read(opts ...runtime.ReadOption) ([]*runtime.Service, error) { 164 var options runtime.ReadOptions 165 for _, o := range opts { 166 o(&options) 167 } 168 if options.Context == nil { 169 options.Context = context.Background() 170 } 171 172 // runtime service create request 173 req := &pb.ReadRequest{ 174 Options: &pb.ReadOptions{ 175 Service: options.Service, 176 Version: options.Version, 177 Type: options.Type, 178 }, 179 } 180 181 resp, err := s.runtime.Read(options.Context, req) 182 if err != nil { 183 return nil, err 184 } 185 186 services := make([]*runtime.Service, 0, len(resp.Services)) 187 for _, service := range resp.Services { 188 svc := &runtime.Service{ 189 Name: service.Name, 190 Version: service.Version, 191 Source: service.Source, 192 Metadata: service.Metadata, 193 } 194 services = append(services, svc) 195 } 196 197 return services, nil 198 } 199 200 // Update updates the running service 201 func (s *svc) Update(svc *runtime.Service, opts ...runtime.UpdateOption) error { 202 var options runtime.UpdateOptions 203 for _, o := range opts { 204 o(&options) 205 } 206 if options.Context == nil { 207 options.Context = context.Background() 208 } 209 210 // runtime service create request 211 req := &pb.UpdateRequest{ 212 Service: &pb.Service{ 213 Name: svc.Name, 214 Version: svc.Version, 215 Source: svc.Source, 216 Metadata: svc.Metadata, 217 }, 218 } 219 220 if _, err := s.runtime.Update(options.Context, req); err != nil { 221 return err 222 } 223 224 return nil 225 } 226 227 // Delete stops and removes the service from the runtime 228 func (s *svc) Delete(svc *runtime.Service, opts ...runtime.DeleteOption) error { 229 var options runtime.DeleteOptions 230 for _, o := range opts { 231 o(&options) 232 } 233 if options.Context == nil { 234 options.Context = context.Background() 235 } 236 237 // runtime service create request 238 req := &pb.DeleteRequest{ 239 Service: &pb.Service{ 240 Name: svc.Name, 241 Version: svc.Version, 242 Source: svc.Source, 243 Metadata: svc.Metadata, 244 }, 245 } 246 247 if _, err := s.runtime.Delete(options.Context, req); err != nil { 248 return err 249 } 250 251 return nil 252 } 253 254 // Start starts the runtime 255 func (s *svc) Start() error { 256 // NOTE: nothing to be done here 257 return nil 258 } 259 260 // Stop stops the runtime 261 func (s *svc) Stop() error { 262 // NOTE: nothing to be done here 263 return nil 264 } 265 266 // Returns the runtime service implementation 267 func (s *svc) String() string { 268 return "service" 269 } 270 271 // NewRuntime creates new service runtime and returns it 272 func NewRuntime(opts ...runtime.Option) runtime.Runtime { 273 var options runtime.Options 274 275 for _, o := range opts { 276 o(&options) 277 } 278 if options.Client == nil { 279 options.Client = client.DefaultClient 280 } 281 282 return &svc{ 283 options: options, 284 runtime: pb.NewRuntimeService(runtime.DefaultName, options.Client), 285 } 286 }