feat(server): properly reschedule jobs after polling
parent
c57de4d8ee
commit
0a5c4295e0
|
@ -8,12 +8,16 @@ import util
|
|||
|
||||
struct BuildJob {
|
||||
pub:
|
||||
// Earliest point this
|
||||
// Next timestamp from which point this job is allowed to be executed
|
||||
timestamp time.Time
|
||||
config BuildConfig
|
||||
// Required for calculating next timestamp after having pop'ed a job
|
||||
ce CronExpression
|
||||
// Actual build config sent to the agent
|
||||
config BuildConfig
|
||||
}
|
||||
|
||||
// Overloaded operator for comparing ScheduledBuild objects
|
||||
// Allows BuildJob structs to be sorted according to their timestamp in
|
||||
// MinHeaps
|
||||
fn (r1 BuildJob) < (r2 BuildJob) bool {
|
||||
return r1.timestamp < r2.timestamp
|
||||
}
|
||||
|
@ -39,7 +43,9 @@ pub fn new_job_queue(default_schedule CronExpression, default_base_image string)
|
|||
}
|
||||
}
|
||||
|
||||
// insert a new job into the queue for a given target on an architecture.
|
||||
// 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) ! {
|
||||
lock q.mutex {
|
||||
if arch !in q.queues {
|
||||
|
@ -58,6 +64,7 @@ pub fn (mut q BuildJobQueue) insert(target Target, arch string) ! {
|
|||
|
||||
job := BuildJob{
|
||||
timestamp: timestamp
|
||||
ce: ce
|
||||
config: BuildConfig{
|
||||
target_id: target.id
|
||||
kind: target.kind
|
||||
|
@ -69,10 +76,25 @@ pub fn (mut q BuildJobQueue) insert(target Target, arch string) ! {
|
|||
}
|
||||
}
|
||||
|
||||
dump(job)
|
||||
q.queues[arch].insert(job)
|
||||
}
|
||||
}
|
||||
|
||||
// reschedule the given job by calculating the next timestamp and re-adding it
|
||||
// to its respective queue. This function is called by the pop functions
|
||||
// *after* having pop'ed the job.
|
||||
fn (mut q BuildJobQueue) reschedule(job BuildJob, arch string) ! {
|
||||
new_timestamp := job.ce.next_from_now()!
|
||||
|
||||
new_job := BuildJob{
|
||||
...job
|
||||
timestamp: new_timestamp
|
||||
}
|
||||
|
||||
q.queues[arch].insert(new_job)
|
||||
}
|
||||
|
||||
// peek shows the first job for the given architecture that's ready to be
|
||||
// executed, if present.
|
||||
pub fn (q &BuildJobQueue) peek(arch string) ?BuildJob {
|
||||
|
@ -99,10 +121,17 @@ pub fn (mut q BuildJobQueue) pop(arch string) ?BuildJob {
|
|||
return none
|
||||
}
|
||||
|
||||
job := q.queues[arch].peek() or { return none }
|
||||
mut job := q.queues[arch].peek() or { return none }
|
||||
|
||||
if job.timestamp < time.now() {
|
||||
return q.queues[arch].pop()
|
||||
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 {}
|
||||
|
||||
return job
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,10 +148,15 @@ pub fn (mut q BuildJobQueue) pop_n(arch string, n int) []BuildJob {
|
|||
mut out := []BuildJob{}
|
||||
|
||||
for out.len < n {
|
||||
job := q.queues[arch].peek() or { break }
|
||||
mut job := q.queues[arch].peek() or { break }
|
||||
|
||||
if job.timestamp < time.now() {
|
||||
out << q.queues[arch].pop() or { break }
|
||||
job = q.queues[arch].pop() or { break }
|
||||
|
||||
// TODO idem
|
||||
q.reschedule(job, arch) or {}
|
||||
|
||||
out << job
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ import web.response { new_data_response, new_response }
|
|||
// import util
|
||||
// import models { BuildLog, BuildLogFilter }
|
||||
|
||||
['/api/v1/builds/poll'; auth; get]
|
||||
fn (mut app App) v1_poll_build_queue() web.Result {
|
||||
['/api/v1/jobs/poll'; auth; get]
|
||||
fn (mut app App) v1_poll_job_queue() web.Result {
|
||||
arch := app.query['arch'] or {
|
||||
return app.json(.bad_request, new_response('Missing arch query arg.'))
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ fn (mut app App) v1_poll_build_queue() web.Result {
|
|||
}
|
||||
max := max_str.int()
|
||||
|
||||
mut out := app.job_queue.pop_n(arch, max)
|
||||
mut out := app.job_queue.pop_n(arch, max).map(it.config)
|
||||
|
||||
return app.json(.ok, new_data_response(out))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue