feat(server): initialize job queue on start; api endpoint for polling

jobs
This commit is contained in:
Jef Roosens 2022-12-12 20:33:51 +01:00 committed by Chewing_Bever
parent 9a49d96e20
commit c57de4d8ee
Signed by untrusted user: Jef Roosens
GPG key ID: B75D4F293C7052DB
3 changed files with 129 additions and 86 deletions

View file

@ -4,6 +4,7 @@ import models { Target }
import cron.expression { CronExpression, parse_expression }
import time
import datatypes { MinHeap }
import util
struct BuildJob {
pub:
@ -23,6 +24,7 @@ pub struct BuildJobQueue {
// Base image to use for targets without defined base image
default_base_image string
mut:
mutex shared util.Dummy
// For each architecture, a priority queue is tracked
queues map[string]MinHeap<BuildJob>
// Each queued build job is also stored in a map, with the keys being the
@ -39,32 +41,95 @@ 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.
pub fn (mut q BuildJobQueue) insert(target Target, arch string) ! {
if arch !in q.queues {
q.queues[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()")
lock q.mutex {
if arch !in q.queues {
q.queues[arch] = MinHeap<BuildJob>{}
}
} else {
q.default_schedule
}
timestamp := ce.next_from_now()!
job := BuildJob{
timestamp: timestamp
config: BuildConfig{
target_id: target.id
kind: target.kind
url: target.url
branch: target.branch
repo: target.repo
// TODO make this configurable
base_image: q.default_base_image
ce := if target.schedule != '' {
parse_expression(target.schedule) or {
return error("Error while parsing cron expression '$target.schedule' (id $target.id): $err.msg()")
}
} else {
q.default_schedule
}
}
q.queues[arch].insert(job)
timestamp := ce.next_from_now()!
job := BuildJob{
timestamp: timestamp
config: BuildConfig{
target_id: target.id
kind: target.kind
url: target.url
branch: target.branch
repo: target.repo
// TODO make this configurable
base_image: q.default_base_image
}
}
q.queues[arch].insert(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 {
rlock q.mutex {
if arch !in q.queues {
return none
}
job := q.queues[arch].peek() or { return none }
if job.timestamp < time.now() {
return job
}
}
return none
}
// pop removes the first job for the given architecture that's ready to be
// executed from the queue and returns it, if present.
pub fn (mut q BuildJobQueue) pop(arch string) ?BuildJob {
lock q.mutex {
if arch !in q.queues {
return none
}
job := q.queues[arch].peek() or { return none }
if job.timestamp < time.now() {
return q.queues[arch].pop()
}
}
return none
}
// pop_n tries to pop at most n available jobs for the given architecture.
pub fn (mut q BuildJobQueue) pop_n(arch string, n int) []BuildJob {
lock q.mutex {
if arch !in q.queues {
return []
}
mut out := []BuildJob{}
for out.len < n {
job := q.queues[arch].peek() or { break }
if job.timestamp < time.now() {
out << q.queues[arch].pop() or { break }
} else {
break
}
}
return out
}
return []
}