1
0
mirror of https://github.com/ohwgiles/laminar.git synced 2026-10-23 11:59:56 +00:00

job leader process

Implement a separate process, the "leader", which runs all the
scripts for a job run, instead of directly from the main laminard
process. This makes for a cleaner process tree view, where the
owning job for a given script is clear; also the leader process
acts as a subreaper to clean up any wayward descendent processes.

Resolves #78.
This commit is contained in:
Oliver Giles
2019-12-21 15:29:37 +02:00
parent 304ef797b8
commit 3fde38c6b8
16 changed files with 600 additions and 409 deletions

View File

@@ -581,16 +581,14 @@ std::shared_ptr<Run> Laminar::queueJob(std::string name, ParamMap params) {
}
bool Laminar::abort(std::string job, uint buildNum) {
if(Run* run = activeRun(job, buildNum)) {
run->abort(true);
return true;
}
if(Run* run = activeRun(job, buildNum))
return run->abort();
return false;
}
void Laminar::abortAll() {
for(std::shared_ptr<Run> run : activeJobs) {
run->abort(false);
run->abort();
}
}
@@ -598,7 +596,9 @@ bool Laminar::tryStartRun(std::shared_ptr<Run> run, int queueIndex) {
for(auto& sc : contexts) {
std::shared_ptr<Context> ctx = sc.second;
if(ctx->canQueue(jobContexts.at(run->name)) && run->configure(buildNums[run->name] + 1, ctx, *fsHome)) {
if(ctx->canQueue(jobContexts.at(run->name))) {
kj::Promise<RunState> onRunFinished = run->start(buildNums[run->name] + 1, ctx, *fsHome,[this](kj::Maybe<pid_t>& pid){return srv.onChildExit(pid);});
ctx->busyExecutors++;
// set the last known result if exists
db->stmt("SELECT result FROM builds WHERE name = ? ORDER BY completedAt DESC LIMIT 1")
@@ -607,13 +607,20 @@ bool Laminar::tryStartRun(std::shared_ptr<Run> run, int queueIndex) {
run->lastResult = RunState(result);
});
// Actually schedules the Run steps
kj::Promise<void> exec = handleRunStep(run.get()).then([=]{
runFinished(run.get());
kj::Promise<void> exec = srv.readDescriptor(run->output_fd, [this, run](const char*b, size_t n){
// handle log output
std::string s(b, n);
run->log += s;
http->notifyLog(run->name, run->build, s, false);
}).then([run, p = kj::mv(onRunFinished)]() mutable {
// wait until leader reaped
return kj::mv(p);
}).then([this, run](RunState){
handleRunFinished(run.get());
});
if(run->timeout > 0) {
exec = exec.attach(srv.addTimeout(run->timeout, [r=run.get()](){
r->abort(true);
r->abort();
}));
}
srv.addTask(kj::mv(exec));
@@ -657,31 +664,7 @@ void Laminar::assignNewJobs() {
}
}
kj::Promise<void> Laminar::handleRunStep(Run* run) {
if(run->step()) {
// no more steps
return kj::READY_NOW;
}
kj::Promise<int> exited = srv.onChildExit(run->current_pid);
// promise is fulfilled when the process is reaped. But first we wait for all
// output from the pipe (Run::output_fd) to be consumed.
return srv.readDescriptor(run->output_fd, [this,run](const char*b,size_t n){
// handle log output
std::string s(b, n);
run->log += s;
http->notifyLog(run->name, run->build, s, false);
}).then([p = std::move(exited)]() mutable {
// wait until the process is reaped
return kj::mv(p);
}).then([this, run](int status){
run->reaped(status);
// next step in Run
return handleRunStep(run);
});
}
void Laminar::runFinished(Run * r) {
void Laminar::handleRunFinished(Run * r) {
std::shared_ptr<Context> ctx = r->context;
ctx->busyExecutors--;