Commit 55f80987 authored by Kamil Trzciński's avatar Kamil Trzciński 🔴

Make to use context to abort all operations

parent ea19ca6e
......@@ -12,6 +12,7 @@ import (
"github.com/Sirupsen/logrus"
"gitlab.com/gitlab-org/gitlab-ci-multi-runner/helpers"
"gitlab.com/hackwaw-disrupt/golang-proxy-server/Godeps/_workspace/src/golang.org/x/net/context"
)
type GitStrategy int
......@@ -138,7 +139,7 @@ func (b *Build) StartBuild(rootDir, cacheDir string, sharedDir bool) {
b.CacheDir = path.Join(cacheDir, b.ProjectUniqueDir(false))
}
func (b *Build) executeStage(buildStage BuildStage, executor Executor, abort chan interface{}) error {
func (b *Build) executeStage(ctx context.Context, buildStage BuildStage, executor Executor) error {
b.CurrentStage = buildStage
shell := executor.Shell()
......@@ -157,8 +158,8 @@ func (b *Build) executeStage(buildStage BuildStage, executor Executor, abort cha
}
cmd := ExecutorCommand{
Context: ctx,
Script: script,
Abort: abort,
}
switch buildStage {
......@@ -171,7 +172,7 @@ func (b *Build) executeStage(buildStage BuildStage, executor Executor, abort cha
return executor.Run(cmd)
}
func (b *Build) executeUploadArtifacts(state error, executor Executor, abort chan interface{}) (err error) {
func (b *Build) executeUploadArtifacts(ctx context.Context, state error, executor Executor) (err error) {
jobState := state
for _, artifacts := range b.Artifacts {
......@@ -179,12 +180,12 @@ func (b *Build) executeUploadArtifacts(state error, executor Executor, abort cha
if state == nil {
// Previous stages were successful
if when == "" || when == ArtifactWhenOnSuccess || when == ArtifactWhenAlways {
state = b.executeStage(BuildStageUploadArtifacts, executor, abort)
state = b.executeStage(ctx, BuildStageUploadArtifacts, executor)
}
} else {
// Previous stage did fail
if when == ArtifactWhenOnFailure || when == ArtifactWhenAlways {
err = b.executeStage(BuildStageUploadArtifacts, executor, abort)
err = b.executeStage(ctx, BuildStageUploadArtifacts, executor)
}
}
}
......@@ -196,67 +197,70 @@ func (b *Build) executeUploadArtifacts(state error, executor Executor, abort cha
return
}
func (b *Build) executeScript(executor Executor, abort chan interface{}) error {
func (b *Build) executeScript(ctx context.Context, executor Executor) error {
// Prepare stage
err := b.executeStage(BuildStagePrepare, executor, abort)
err := b.executeStage(ctx, BuildStagePrepare, executor)
if err == nil {
err = b.attemptExecuteStage(BuildStageGetSources, executor, abort, b.GetGetSourcesAttempts())
err = b.attemptExecuteStage(ctx, BuildStageGetSources, executor, b.GetGetSourcesAttempts())
}
if err == nil {
err = b.attemptExecuteStage(BuildStageDownloadArtifacts, executor, abort, b.GetDownloadArtifactsAttempts())
err = b.attemptExecuteStage(ctx, BuildStageDownloadArtifacts, executor, b.GetDownloadArtifactsAttempts())
}
if err == nil {
err = b.attemptExecuteStage(BuildStageRestoreCache, executor, abort, b.GetRestoreCacheAttempts())
err = b.attemptExecuteStage(ctx, BuildStageRestoreCache, executor, b.GetRestoreCacheAttempts())
}
if err == nil {
// Execute user build script (before_script + script)
err = b.executeStage(BuildStageUserScript, executor, abort)
err = b.executeStage(ctx, BuildStageUserScript, executor)
// Execute after script (after_script)
timeoutCh := make(chan interface{}, 1)
timeout := time.AfterFunc(time.Minute*5, func() {
close(timeoutCh)
})
b.executeStage(BuildStageAfterScript, executor, timeoutCh)
timeout.Stop()
timeoutContext, timeoutCancel := context.WithTimeout(ctx, AfterScriptTimeout)
defer timeoutCancel()
b.executeStage(timeoutContext, BuildStageAfterScript, executor)
}
// Execute post script (cache store, artifacts upload)
if err == nil {
err = b.executeStage(BuildStageArchiveCache, executor, abort)
err = b.executeStage(ctx, BuildStageArchiveCache, executor)
}
err = b.executeUploadArtifacts(err, executor, abort)
err = b.executeUploadArtifacts(ctx, err, executor)
return err
}
func (b *Build) attemptExecuteStage(buildStage BuildStage, executor Executor, abort chan interface{}, attempts int) (err error) {
func (b *Build) attemptExecuteStage(ctx context.Context, buildStage BuildStage, executor Executor, attempts int) (err error) {
if attempts < 1 || attempts > 10 {
return fmt.Errorf("Number of attempts out of the range [1, 10] for stage: %s", buildStage)
}
for attempt := 0; attempt < attempts; attempt++ {
if err = b.executeStage(buildStage, executor, abort); err == nil {
if err = b.executeStage(ctx, buildStage, executor); err == nil {
return
}
}
return
}
func (b *Build) run(executor Executor) (err error) {
b.CurrentState = BuildRunRuntimeRunning
func (b *Build) GetBuildTimeout() time.Duration {
buildTimeout := b.RunnerInfo.Timeout
if buildTimeout <= 0 {
buildTimeout = DefaultTimeout
}
return time.Duration(buildTimeout) * time.Second
}
func (b *Build) run(ctx context.Context, executor Executor) (err error) {
b.CurrentState = BuildRunRuntimeRunning
buildFinish := make(chan error, 1)
buildAbort := make(chan interface{})
runContext, runCancel := context.WithCancel(context.Background())
defer runCancel()
// Run build script
go func() {
buildFinish <- b.executeScript(executor, buildAbort)
buildFinish <- b.executeScript(runContext, executor)
}()
// Wait for signals: cancel, timeout, abort or finish
......@@ -266,9 +270,9 @@ func (b *Build) run(executor Executor) (err error) {
err = &BuildError{Inner: errors.New("canceled")}
b.CurrentState = BuildRunRuntimeCanceled
case <-time.After(time.Duration(buildTimeout) * time.Second):
err = &BuildError{Inner: fmt.Errorf("execution took longer than %v seconds", buildTimeout)}
b.CurrentState = BuildRunRuntimeTimedout
case <-ctx.Done():
err = &BuildError{Inner: fmt.Errorf("execution took longer than %v seconds", b.GetBuildTimeout())}
b.CurrentStage = BuildRunRuntimeTimedout
case signal := <-b.SystemInterrupt:
err = fmt.Errorf("aborted: %v", signal)
......@@ -282,23 +286,12 @@ func (b *Build) run(executor Executor) (err error) {
b.Log().WithError(err).Debugln("Waiting for build to finish...")
// Wait till we receive that build did finish
for {
select {
case buildAbort <- true:
case <-buildFinish:
return err
}
}
runCancel()
<-buildFinish
return err
}
func (b *Build) retryCreateExecutor(globalConfig *Config, provider ExecutorProvider, logger BuildLogger) (executor Executor, err error) {
options := ExecutorPrepareOptions{
Config: b.Runner,
Build: b,
Trace: b.Trace,
User: globalConfig.User,
}
func (b *Build) retryCreateExecutor(options ExecutorPrepareOptions, provider ExecutorProvider, logger BuildLogger) (executor Executor, err error) {
for tries := 0; tries < PreparationRetries; tries++ {
executor = provider.Create()
if executor == nil {
......@@ -361,6 +354,17 @@ func (b *Build) Run(globalConfig *Config, trace JobTrace) (err error) {
}
}()
context, cancel := context.WithTimeout(context.Background(), b.GetBuildTimeout())
defer cancel()
options := ExecutorPrepareOptions{
Config: b.Runner,
Build: b,
Trace: b.Trace,
User: globalConfig.User,
Context: context,
}
b.Trace = trace
provider := GetExecutor(b.Runner.Executor)
......@@ -368,9 +372,9 @@ func (b *Build) Run(globalConfig *Config, trace JobTrace) (err error) {
return errors.New("executor not found")
}
executor, err = b.retryCreateExecutor(globalConfig, provider, logger)
executor, err = b.retryCreateExecutor(options, provider, logger)
if err == nil {
err = b.run(executor)
err = b.run(context, executor)
}
if executor != nil {
executor.Finish(err)
......
......@@ -21,5 +21,6 @@ const DefaultArtifactDownloadAttempts = 1
const DefaultRestoreCacheAttempts = 1
const KubernetesPollInterval = 3
const KubernetesPollTimeout = 180
const AfterScriptTimeout = 5 * time.Second
var PreparationRetryInterval = 3 * time.Second
......@@ -10,7 +10,6 @@ type ExecutorData interface{}
type ExecutorCommand struct {
Script string
Predefined bool
Abort chan interface{}
Context context.Context
}
......
......@@ -140,14 +140,16 @@ func (s *executor) Run(cmd common.ExecutorCommand) error {
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
select {
case err := <-s.runInContainer(ctx, containerName, cmd.Script):
if err != nil && strings.Contains(err.Error(), "executing in Docker Container") {
return &common.BuildError{Inner: err}
}
return err
case <-cmd.Abort:
cancel()
case <-cmd.Context.Done():
return fmt.Errorf("build aborted")
}
}
......
......@@ -120,7 +120,7 @@ func (s *executor) Run(cmd common.ExecutorCommand) error {
case err = <-waitCh:
return err
case <-cmd.Abort:
case <-cmd.Context.Done():
return s.killAndWait(c, waitCh)
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment