forked from vieter-v/vieter
Merge pull request 'Implement global build timeout' (#358) from Chewing_Bever/vieter:build-timeout into dev
Reviewed-on: vieter-v/vieter#358
commit
de8764b281
|
@ -94,8 +94,8 @@ pub:
|
||||||
}
|
}
|
||||||
|
|
||||||
// build_target builds the given target. Internally it calls `build_config`.
|
// build_target builds the given target. Internally it calls `build_config`.
|
||||||
pub fn build_target(address string, api_key string, base_image_id string, target &Target, force bool) !BuildResult {
|
pub fn build_target(address string, api_key string, base_image_id string, target &Target, force bool, timeout int) !BuildResult {
|
||||||
config := target.as_build_config(base_image_id, force)
|
config := target.as_build_config(base_image_id, force, timeout)
|
||||||
|
|
||||||
return build_config(address, api_key, config)
|
return build_config(address, api_key, config)
|
||||||
}
|
}
|
||||||
|
@ -136,9 +136,17 @@ pub fn build_config(address string, api_key string, config BuildConfig) !BuildRe
|
||||||
dd.container_start(id)!
|
dd.container_start(id)!
|
||||||
|
|
||||||
mut data := dd.container_inspect(id)!
|
mut data := dd.container_inspect(id)!
|
||||||
|
start_time := time.now()
|
||||||
|
|
||||||
// This loop waits until the container has stopped, so we can remove it after
|
// This loop waits until the container has stopped, so we can remove it after
|
||||||
for data.state.running {
|
for data.state.running {
|
||||||
|
if time.now() - start_time > config.timeout * time.second {
|
||||||
|
dd.container_kill(id)!
|
||||||
|
dd.container_remove(id)!
|
||||||
|
|
||||||
|
return error('Build killed due to timeout (${config.timeout}s)')
|
||||||
|
}
|
||||||
|
|
||||||
time.sleep(1 * time.second)
|
time.sleep(1 * time.second)
|
||||||
|
|
||||||
data = dd.container_inspect(id)!
|
data = dd.container_inspect(id)!
|
||||||
|
|
|
@ -33,6 +33,8 @@ pub struct BuildJobQueue {
|
||||||
default_schedule &cron.Expression
|
default_schedule &cron.Expression
|
||||||
// Base image to use for targets without defined base image
|
// Base image to use for targets without defined base image
|
||||||
default_base_image string
|
default_base_image string
|
||||||
|
// After how many minutes a build should be forcefully cancelled
|
||||||
|
default_build_timeout int
|
||||||
mut:
|
mut:
|
||||||
mutex shared util.Dummy
|
mutex shared util.Dummy
|
||||||
// For each architecture, a priority queue is tracked
|
// For each architecture, a priority queue is tracked
|
||||||
|
@ -44,10 +46,11 @@ mut:
|
||||||
}
|
}
|
||||||
|
|
||||||
// new_job_queue initializes a new job queue
|
// new_job_queue initializes a new job queue
|
||||||
pub fn new_job_queue(default_schedule &cron.Expression, default_base_image string) BuildJobQueue {
|
pub fn new_job_queue(default_schedule &cron.Expression, default_base_image string, default_build_timeout int) BuildJobQueue {
|
||||||
return BuildJobQueue{
|
return BuildJobQueue{
|
||||||
default_schedule: unsafe { default_schedule }
|
default_schedule: unsafe { default_schedule }
|
||||||
default_base_image: default_base_image
|
default_base_image: default_base_image
|
||||||
|
default_build_timeout: default_build_timeout
|
||||||
invalidated: map[int]time.Time{}
|
invalidated: map[int]time.Time{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +83,7 @@ pub fn (mut q BuildJobQueue) insert(input InsertConfig) ! {
|
||||||
mut job := BuildJob{
|
mut job := BuildJob{
|
||||||
created: time.now()
|
created: time.now()
|
||||||
single: input.single
|
single: input.single
|
||||||
config: input.target.as_build_config(q.default_base_image, input.force)
|
config: input.target.as_build_config(q.default_base_image, input.force, q.default_build_timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !input.now {
|
if !input.now {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import os
|
||||||
import build
|
import build
|
||||||
|
|
||||||
// build locally builds the target with the given id.
|
// build locally builds the target with the given id.
|
||||||
fn build_target(conf Config, target_id int, force bool) ! {
|
fn build_target(conf Config, target_id int, force bool, timeout int) ! {
|
||||||
c := client.new(conf.address, conf.api_key)
|
c := client.new(conf.address, conf.api_key)
|
||||||
target := c.get_target(target_id)!
|
target := c.get_target(target_id)!
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ fn build_target(conf Config, target_id int, force bool) ! {
|
||||||
image_id := build.create_build_image(conf.base_image)!
|
image_id := build.create_build_image(conf.base_image)!
|
||||||
|
|
||||||
println('Running build...')
|
println('Running build...')
|
||||||
res := build.build_target(conf.address, conf.api_key, image_id, target, force)!
|
res := build.build_target(conf.address, conf.api_key, image_id, target, force, timeout)!
|
||||||
|
|
||||||
println('Removing build image...')
|
println('Removing build image...')
|
||||||
|
|
||||||
|
|
|
@ -232,6 +232,12 @@ pub fn cmd() cli.Command {
|
||||||
description: 'Architecture to schedule build for. Required when using -remote.'
|
description: 'Architecture to schedule build for. Required when using -remote.'
|
||||||
flag: cli.FlagType.string
|
flag: cli.FlagType.string
|
||||||
},
|
},
|
||||||
|
cli.Flag{
|
||||||
|
name: 'timeout'
|
||||||
|
description: 'After how many minutes to cancel the build. Only applies to local builds.'
|
||||||
|
flag: cli.FlagType.int
|
||||||
|
default_value: ['3600']
|
||||||
|
},
|
||||||
]
|
]
|
||||||
execute: fn (cmd cli.Command) ! {
|
execute: fn (cmd cli.Command) ! {
|
||||||
config_file := cmd.flags.get_string('config-file')!
|
config_file := cmd.flags.get_string('config-file')!
|
||||||
|
@ -239,6 +245,7 @@ pub fn cmd() cli.Command {
|
||||||
|
|
||||||
remote := cmd.flags.get_bool('remote')!
|
remote := cmd.flags.get_bool('remote')!
|
||||||
force := cmd.flags.get_bool('force')!
|
force := cmd.flags.get_bool('force')!
|
||||||
|
timeout := cmd.flags.get_int('timeout')!
|
||||||
target_id := cmd.args[0].int()
|
target_id := cmd.args[0].int()
|
||||||
|
|
||||||
if remote {
|
if remote {
|
||||||
|
@ -251,7 +258,7 @@ pub fn cmd() cli.Command {
|
||||||
c := client.new(conf_.address, conf_.api_key)
|
c := client.new(conf_.address, conf_.api_key)
|
||||||
c.queue_job(target_id, arch, force)!
|
c.queue_job(target_id, arch, force)!
|
||||||
} else {
|
} else {
|
||||||
build_target(conf_, target_id, force)!
|
build_target(conf_, target_id, force, timeout)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,9 +10,10 @@ pub:
|
||||||
repo string
|
repo string
|
||||||
base_image string
|
base_image string
|
||||||
force bool
|
force bool
|
||||||
|
timeout int
|
||||||
}
|
}
|
||||||
|
|
||||||
// str return a single-line string representation of a build log
|
// str return a single-line string representation of a build log
|
||||||
pub fn (c BuildConfig) str() string {
|
pub fn (c BuildConfig) str() string {
|
||||||
return '{ target: ${c.target_id}, kind: ${c.kind}, url: ${c.url}, branch: ${c.branch}, path: ${c.path}, repo: ${c.repo}, base_image: ${c.base_image}, force: ${c.force} }'
|
return '{ target: ${c.target_id}, kind: ${c.kind}, url: ${c.url}, branch: ${c.branch}, path: ${c.path}, repo: ${c.repo}, base_image: ${c.base_image}, force: ${c.force}, timeout: ${c.timeout} }'
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ pub fn (t &Target) str() string {
|
||||||
|
|
||||||
// as_build_config converts a Target into a BuildConfig, given some extra
|
// as_build_config converts a Target into a BuildConfig, given some extra
|
||||||
// needed information.
|
// needed information.
|
||||||
pub fn (t &Target) as_build_config(base_image string, force bool) BuildConfig {
|
pub fn (t &Target) as_build_config(base_image string, force bool, timeout int) BuildConfig {
|
||||||
return BuildConfig{
|
return BuildConfig{
|
||||||
target_id: t.id
|
target_id: t.id
|
||||||
kind: t.kind
|
kind: t.kind
|
||||||
|
@ -64,6 +64,7 @@ pub fn (t &Target) as_build_config(base_image string, force bool) BuildConfig {
|
||||||
repo: t.repo
|
repo: t.repo
|
||||||
base_image: base_image
|
base_image: base_image
|
||||||
force: force
|
force: force
|
||||||
|
timeout: timeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ pub:
|
||||||
max_log_age int [empty_default]
|
max_log_age int [empty_default]
|
||||||
log_removal_schedule string = '0 0'
|
log_removal_schedule string = '0 0'
|
||||||
collect_metrics bool [empty_default]
|
collect_metrics bool [empty_default]
|
||||||
|
default_build_timeout int = 3600
|
||||||
}
|
}
|
||||||
|
|
||||||
// cmd returns the cli submodule that handles starting the server
|
// cmd returns the cli submodule that handles starting the server
|
||||||
|
|
|
@ -108,7 +108,7 @@ pub fn server(conf Config) ! {
|
||||||
repo: repo_
|
repo: repo_
|
||||||
db: db
|
db: db
|
||||||
collector: collector
|
collector: collector
|
||||||
job_queue: build.new_job_queue(global_ce, conf.base_image)
|
job_queue: build.new_job_queue(global_ce, conf.base_image, conf.default_build_timeout)
|
||||||
}
|
}
|
||||||
app.init_job_queue() or {
|
app.init_job_queue() or {
|
||||||
util.exit_with_message(1, 'Failed to inialize job queue: ${err.msg()}')
|
util.exit_with_message(1, 'Failed to inialize job queue: ${err.msg()}')
|
||||||
|
|
Loading…
Reference in New Issue