github.com/docker/libcompose@v0.4.1-0.20210616120443-2a046c0bdbf2/project/service-wrapper.go (about)

     1  package project
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/docker/libcompose/project/events"
     7  	log "github.com/sirupsen/logrus"
     8  )
     9  
    10  type serviceWrapper struct {
    11  	name    string
    12  	service Service
    13  	done    sync.WaitGroup
    14  	state   ServiceState
    15  	err     error
    16  	project *Project
    17  	noWait  bool
    18  	ignored map[string]bool
    19  }
    20  
    21  func newServiceWrapper(name string, p *Project) (*serviceWrapper, error) {
    22  	wrapper := &serviceWrapper{
    23  		name:    name,
    24  		state:   StateUnknown,
    25  		project: p,
    26  		ignored: map[string]bool{},
    27  	}
    28  
    29  	return wrapper, wrapper.Reset()
    30  }
    31  
    32  func (s *serviceWrapper) IgnoreDep(name string) {
    33  	s.ignored[name] = true
    34  }
    35  
    36  func (s *serviceWrapper) Reset() error {
    37  	if s.state != StateExecuted {
    38  		service, err := s.project.CreateService(s.name)
    39  		if err != nil {
    40  			log.Errorf("Failed to create service for %s : %v", s.name, err)
    41  			return err
    42  		}
    43  
    44  		s.service = service
    45  	}
    46  
    47  	if s.err == ErrRestart {
    48  		s.err = nil
    49  	}
    50  	s.done.Add(1)
    51  
    52  	return nil
    53  }
    54  
    55  func (s *serviceWrapper) Ignore() {
    56  	defer s.done.Done()
    57  
    58  	s.state = StateExecuted
    59  	s.project.Notify(events.ServiceUpIgnored, s.service.Name(), nil)
    60  }
    61  
    62  func (s *serviceWrapper) waitForDeps(wrappers map[string]*serviceWrapper) bool {
    63  	if s.noWait {
    64  		return true
    65  	}
    66  
    67  	for _, dep := range s.service.DependentServices() {
    68  		if s.ignored[dep.Target] {
    69  			continue
    70  		}
    71  
    72  		if wrapper, ok := wrappers[dep.Target]; ok {
    73  			if wrapper.Wait() == ErrRestart {
    74  				s.project.Notify(events.ProjectReload, wrapper.service.Name(), nil)
    75  				s.err = ErrRestart
    76  				return false
    77  			}
    78  		} else {
    79  			log.Errorf("Failed to find %s", dep.Target)
    80  		}
    81  	}
    82  
    83  	return true
    84  }
    85  
    86  func (s *serviceWrapper) Do(wrappers map[string]*serviceWrapper, start, done events.EventType, action func(service Service) error) {
    87  	defer s.done.Done()
    88  
    89  	if s.state == StateExecuted {
    90  		return
    91  	}
    92  
    93  	if wrappers != nil && !s.waitForDeps(wrappers) {
    94  		return
    95  	}
    96  
    97  	s.state = StateExecuted
    98  
    99  	s.project.Notify(start, s.service.Name(), nil)
   100  
   101  	s.err = action(s.service)
   102  	if s.err == ErrRestart {
   103  		s.project.Notify(done, s.service.Name(), nil)
   104  		s.project.Notify(events.ProjectReloadTrigger, s.service.Name(), nil)
   105  	} else if s.err != nil {
   106  		log.Errorf("Failed %s %s : %v", start, s.name, s.err)
   107  	} else {
   108  		s.project.Notify(done, s.service.Name(), nil)
   109  	}
   110  }
   111  
   112  func (s *serviceWrapper) Wait() error {
   113  	s.done.Wait()
   114  	return s.err
   115  }