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  }