package deployers import ( "context" "errors" "sync/atomic" "time" "gitea.thegux.fr/hmdeploy/models" "github.com/rs/zerolog/log" ) var ErrContextDone = errors.New("unable to execute, context done") type IDeployer interface { Type() DeployerType Deploy() error Build() error Clear() error Error() error Done() <-chan struct{} } type DeployerType string const ( Nginx DeployerType = "nginx" Swarm DeployerType = "swarm" GracefulTimeout = 10 * time.Second ) type deployer struct { ctx context.Context type_ DeployerType project *models.Project processing atomic.Bool chDone chan struct{} errFlag error } func newDeployer(ctx context.Context, type_ DeployerType, project *models.Project) *deployer { d := &deployer{ ctx: ctx, type_: type_, project: project, processing: atomic.Bool{}, chDone: make(chan struct{}, 1), } d.processing.Store(false) return d } func (d *deployer) setDone(err error) { d.chDone <- struct{}{} d.errFlag = err } func (d *deployer) Type() DeployerType { return d.type_ } func (d *deployer) Error() error { return d.errFlag } func (d *deployer) Done() <-chan struct{} { chDone := make(chan struct{}) go func() { defer func() { close(chDone) }() for { select { case <-d.ctx.Done(): log.Warn().Str("deployer", string(d.type_)).Msg("context done catch") timeout := time.NewTicker(GracefulTimeout) tick := time.NewTicker(time.Second) for { select { case <-timeout.C: log.Error(). Str("deployer", string(d.type_)). Msg("timeout while waiting for graceful shutdown") chDone <- struct{}{} return case <-tick.C: if !d.processing.Load() { chDone <- struct{}{} return } tick.Reset(1 * time.Second) } } case <-d.chDone: log.Info().Str("deployer", string(d.type_)).Msg("terminated") chDone <- struct{}{} return } } }() return chDone }