This commit is contained in:
parent
4e28b6048e
commit
022868b7b0
1 changed files with 68 additions and 11 deletions
|
|
@ -5,7 +5,6 @@ use crate::{PartitionRef, WantDetail};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use crate::build_state::BuildState;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Orchestrator turns wants, config, and BEL state into scheduled jobs. It uses lightweight threads +
|
Orchestrator turns wants, config, and BEL state into scheduled jobs. It uses lightweight threads +
|
||||||
|
|
@ -69,7 +68,7 @@ impl<S: BELStorage + Debug> Orchestrator<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Continuously invoked function to watch job run status */
|
/** Continuously invoked function to watch job run status */
|
||||||
fn poll_jobs(&mut self) -> Result<(), Box<dyn Error>> {
|
fn poll_job_runs(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
// Visit existing jobs, remove completed
|
// Visit existing jobs, remove completed
|
||||||
self.job_runs.retain_mut(|jr| {
|
self.job_runs.retain_mut(|jr| {
|
||||||
// Append emitted events
|
// Append emitted events
|
||||||
|
|
@ -146,7 +145,7 @@ impl<S: BELStorage + Debug> Orchestrator<S> {
|
||||||
/** Entrypoint for running jobs */
|
/** Entrypoint for running jobs */
|
||||||
pub fn join(mut self) -> Result<(), Box<dyn Error>> {
|
pub fn join(mut self) -> Result<(), Box<dyn Error>> {
|
||||||
loop {
|
loop {
|
||||||
self.poll_jobs()?;
|
self.poll_job_runs()?;
|
||||||
self.poll_wants()?;
|
self.poll_wants()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -154,48 +153,106 @@ impl<S: BELStorage + Debug> Orchestrator<S> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
mod poll_jobs {
|
// The orchestrator needs to be able to actually execute job runs
|
||||||
|
mod run_jobs {
|
||||||
|
// Use case: the orchestrator should be able to execute a spawned-process job
|
||||||
|
#[test]
|
||||||
|
#[ignore] // TODO define this interface
|
||||||
|
fn test_spawned_process_job() {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The orchestrator relies on polling job run status to react to job completions that imply
|
||||||
|
// key outcomes like:
|
||||||
|
// - Success: partitions produced, other job runs may be schedulable
|
||||||
|
// - Dep miss: wants need to be created
|
||||||
|
// - Failure: engineer likely needs to react
|
||||||
|
mod poll_job_runs {
|
||||||
// Use case: we find a job that has completed, BEL should be written with appropriate event
|
// Use case: we find a job that has completed, BEL should be written with appropriate event
|
||||||
// (both for success and fail cases)
|
// (both for success and fail cases)
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn test_job_completion_events() {
|
fn test_job_completion_events() {
|
||||||
// TODO
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
//Use case: a job has written new stdout, it should produce a new heartbeat event in the BEL
|
//Use case: a job has written new stdout, it should produce a new heartbeat event in the BEL
|
||||||
// TODO - we should come back here later and ensure we have a minimum heartbeat period
|
// TODO - we should come back here later and ensure we have a minimum heartbeat period
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn test_heartbeat_from_stdout() {
|
fn test_heartbeat_from_stdout() {
|
||||||
// TODO
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The orchestrator polls wants so that it can react to new wants created by users, or to wants
|
||||||
|
// created by itself (for dep miss job run failures)
|
||||||
mod poll_wants {
|
mod poll_wants {
|
||||||
// Use case: Empty schedulable wants is a valid case, and should create no new jobs.
|
// Use case: Empty schedulable wants is a valid case, and should create no new jobs.
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn test_empty_wants_noop() {
|
fn test_empty_wants_noop() {
|
||||||
// TODO
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use case: Some schedulable wants with jobs that can be matched should launch those jobs
|
// Use case: Some schedulable wants with jobs that can be matched should launch those jobs
|
||||||
// (but in this case using a noop/mock child process)
|
// (but in this case using a noop/mock child process)
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn test_schedulable_wants_should_schedule() {
|
fn test_schedulable_wants_should_schedule() {
|
||||||
// TODO
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use case: A schedulable want that can't be matched to a job should return an error
|
// Use case: A schedulable want that can't be matched to a job should return an error
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn test_schedulable_want_no_matching_job() {
|
fn test_schedulable_want_no_matching_job() {
|
||||||
// TODO
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod want_group {
|
// Orchestrator want creation is the means of data dependency propagation, allowing the
|
||||||
|
// orchestrator to create partitions needed by jobs that produce the existing wanted partitions.
|
||||||
|
mod want_create {
|
||||||
|
// Use case: The orchestrator should map a failed job into a set of wants
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_job_fail_want_mapping() {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Orchestrator needs to be able to achieve high level orchestration use cases.
|
||||||
|
mod orchestration {
|
||||||
|
// Use case: should run a job to produce a partition in reaction to a want, then have the
|
||||||
|
// want fulfilled.
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_want_builds_partition() {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use case: a graph with multi-hop deps should achieve the multi-hop build
|
||||||
|
// - Job B depends on part_a produced by job A
|
||||||
|
// - Job B should be attempted, fail, and create a want for part_a
|
||||||
|
// - Job A should be attempted, succeed, and produce part_a
|
||||||
|
// - Job B should be attempted, succeed, and produce part_b
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_multi_hop_want_builds_partition() {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The orchestrator groups wants to enable efficient execution. Many individual wants may
|
||||||
|
// reference the same partitions, or many different partitions may be referenced by many
|
||||||
|
// different wants. The orchestrator needs to be able to achieve job run batching, where a
|
||||||
|
// single job run builds multiple partitions from multiple different wants.
|
||||||
|
mod want_grouping {
|
||||||
use super::super::*;
|
use super::super::*;
|
||||||
use crate::build_event_log::MemoryBELStorage;
|
use crate::build_event_log::MemoryBELStorage;
|
||||||
use crate::{PartitionRef, WantDetail};
|
use crate::{PartitionRef, WantDetail};
|
||||||
use crate::build_state::BuildState;
|
|
||||||
|
|
||||||
fn create_job_config(label: &str, pattern: &str) -> JobConfiguration {
|
fn create_job_config(label: &str, pattern: &str) -> JobConfiguration {
|
||||||
JobConfiguration {
|
JobConfiguration {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue