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 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
} }

View File

@ -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)
}

View File

@ -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)!
} }
} }