feat: allow queueing one-time builds

pull/301/head
Jef Roosens 2022-12-13 21:22:22 +01:00
parent f6c5e7c246
commit 6a208dbe6c
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
3 changed files with 51 additions and 18 deletions

View File

@ -16,6 +16,8 @@ pub:
ce CronExpression
// Actual build config sent to the agent
config BuildConfig
// Whether this is a one-time job
single bool
}
// 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.
pub fn (mut q BuildJobQueue) insert_all(target Target) ! {
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
// job will then be endlessly rescheduled after being pop'ed, unless removed
// explicitely.
pub fn (mut q BuildJobQueue) insert(target Target, arch string) ! {
pub fn (mut q BuildJobQueue) insert(input InsertConfig) ! {
lock q.mutex {
if arch !in q.queues {
q.queues[arch] = MinHeap<BuildJob>{}
if input.arch !in q.queues {
q.queues[input.arch] = MinHeap<BuildJob>{}
}
ce := if target.schedule != '' {
parse_expression(target.schedule) or {
return error("Error while parsing cron expression '$target.schedule' (id $target.id): $err.msg()")
ce := if input.target.schedule != '' {
parse_expression(input.target.schedule) or {
return error("Error while parsing cron expression '$input.target.schedule' (id $input.target.id): $err.msg()")
}
} else {
q.default_schedule
@ -80,18 +89,19 @@ pub fn (mut q BuildJobQueue) insert(target Target, arch string) ! {
created: time.now()
timestamp: timestamp
ce: ce
single: input.single
config: BuildConfig{
target_id: target.id
kind: target.kind
url: target.url
branch: target.branch
repo: target.repo
target_id: input.target.id
kind: input.target.kind
url: input.target.url
branch: input.target.branch
repo: input.target.repo
// TODO make this configurable
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() {
job = q.queues[arch].pop()?
// 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
// used before?
q.reschedule(job, arch) or {}
if !job.single {
// 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
// used before?
q.reschedule(job, arch) or {}
}
return job
}

View File

@ -19,3 +19,24 @@ fn (mut app App) v1_poll_job_queue() web.Result {
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)
}

View File

@ -37,7 +37,7 @@ fn (mut app App) init_job_queue() ! {
for targets.len > 0 {
for target in targets {
for arch in target.arch {
app.job_queue.insert(target, arch.value)!
app.job_queue.insert(target: target, arch: arch.value)!
}
}