feat: allow queueing one-time builds
parent
f6c5e7c246
commit
6a208dbe6c
|
@ -16,6 +16,8 @@ pub:
|
||||||
ce CronExpression
|
ce CronExpression
|
||||||
// Actual build config sent to the agent
|
// Actual build config sent to the agent
|
||||||
config BuildConfig
|
config BuildConfig
|
||||||
|
// Whether this is a one-time job
|
||||||
|
single bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allows BuildJob structs to be sorted according to their timestamp in
|
// Allows BuildJob structs to be sorted according to their timestamp in
|
||||||
|
@ -53,22 +55,29 @@ pub fn new_job_queue(default_schedule CronExpression, default_base_image string)
|
||||||
// insert_all executes insert for each architecture of the given Target.
|
// insert_all executes insert for each architecture of the given Target.
|
||||||
pub fn (mut q BuildJobQueue) insert_all(target Target) ! {
|
pub fn (mut q BuildJobQueue) insert_all(target Target) ! {
|
||||||
for arch in target.arch {
|
for arch in target.arch {
|
||||||
q.insert(target, arch.value)!
|
q.insert(target: target, arch: arch.value)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[params]
|
||||||
|
pub struct InsertConfig {
|
||||||
|
target Target [required]
|
||||||
|
arch string [required]
|
||||||
|
single bool
|
||||||
|
}
|
||||||
|
|
||||||
// insert a new target's job into the queue for the given architecture. This
|
// insert a new target's job into the queue for the given architecture. This
|
||||||
// job will then be endlessly rescheduled after being pop'ed, unless removed
|
// job will then be endlessly rescheduled after being pop'ed, unless removed
|
||||||
// explicitely.
|
// explicitely.
|
||||||
pub fn (mut q BuildJobQueue) insert(target Target, arch string) ! {
|
pub fn (mut q BuildJobQueue) insert(input InsertConfig) ! {
|
||||||
lock q.mutex {
|
lock q.mutex {
|
||||||
if arch !in q.queues {
|
if input.arch !in q.queues {
|
||||||
q.queues[arch] = MinHeap<BuildJob>{}
|
q.queues[input.arch] = MinHeap<BuildJob>{}
|
||||||
}
|
}
|
||||||
|
|
||||||
ce := if target.schedule != '' {
|
ce := if input.target.schedule != '' {
|
||||||
parse_expression(target.schedule) or {
|
parse_expression(input.target.schedule) or {
|
||||||
return error("Error while parsing cron expression '$target.schedule' (id $target.id): $err.msg()")
|
return error("Error while parsing cron expression '$input.target.schedule' (id $input.target.id): $err.msg()")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
q.default_schedule
|
q.default_schedule
|
||||||
|
@ -80,18 +89,19 @@ pub fn (mut q BuildJobQueue) insert(target Target, arch string) ! {
|
||||||
created: time.now()
|
created: time.now()
|
||||||
timestamp: timestamp
|
timestamp: timestamp
|
||||||
ce: ce
|
ce: ce
|
||||||
|
single: input.single
|
||||||
config: BuildConfig{
|
config: BuildConfig{
|
||||||
target_id: target.id
|
target_id: input.target.id
|
||||||
kind: target.kind
|
kind: input.target.kind
|
||||||
url: target.url
|
url: input.target.url
|
||||||
branch: target.branch
|
branch: input.target.branch
|
||||||
repo: target.repo
|
repo: input.target.repo
|
||||||
// TODO make this configurable
|
// TODO make this configurable
|
||||||
base_image: q.default_base_image
|
base_image: q.default_base_image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
q.queues[arch].insert(job)
|
q.queues[input.arch].insert(job)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,10 +168,12 @@ pub fn (mut q BuildJobQueue) pop(arch string) ?BuildJob {
|
||||||
if job.timestamp < time.now() {
|
if job.timestamp < time.now() {
|
||||||
job = q.queues[arch].pop()?
|
job = q.queues[arch].pop()?
|
||||||
|
|
||||||
|
if !job.single {
|
||||||
// TODO how do we handle this properly? Is it even possible for a
|
// TODO how do we handle this properly? Is it even possible for a
|
||||||
// cron expression to not return a next time if it's already been
|
// cron expression to not return a next time if it's already been
|
||||||
// used before?
|
// used before?
|
||||||
q.reschedule(job, arch) or {}
|
q.reschedule(job, arch) or {}
|
||||||
|
}
|
||||||
|
|
||||||
return job
|
return job
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,3 +19,24 @@ fn (mut app App) v1_poll_job_queue() web.Result {
|
||||||
|
|
||||||
return app.json(.ok, new_data_response(out))
|
return app.json(.ok, new_data_response(out))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
['/api/v1/jobs/queue'; auth; post]
|
||||||
|
fn (mut app App) v1_queue_job() web.Result {
|
||||||
|
target_id := app.query['target'] or {
|
||||||
|
return app.json(.bad_request, new_response('Missing target query arg.'))
|
||||||
|
}.int()
|
||||||
|
|
||||||
|
arch := app.query['arch'] or {
|
||||||
|
return app.json(.bad_request, new_response('Missing arch query arg.'))
|
||||||
|
}
|
||||||
|
|
||||||
|
target := app.db.get_target(target_id) or {
|
||||||
|
return app.json(.bad_request, new_response('Unknown target id.'))
|
||||||
|
}
|
||||||
|
|
||||||
|
app.job_queue.insert(target: target, arch: arch, single: true) or {
|
||||||
|
return app.status(.internal_server_error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return app.status(.ok)
|
||||||
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ fn (mut app App) init_job_queue() ! {
|
||||||
for targets.len > 0 {
|
for targets.len > 0 {
|
||||||
for target in targets {
|
for target in targets {
|
||||||
for arch in target.arch {
|
for arch in target.arch {
|
||||||
app.job_queue.insert(target, arch.value)!
|
app.job_queue.insert(target: target, arch: arch.value)!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue