Checkpointing work to add JS endpoint
This commit is contained in:
parent
f5ca3315f0
commit
6f5f890b1e
+1
-1
@@ -136,7 +136,7 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
runner.run().await;
|
runner.run(false).await;
|
||||||
|
|
||||||
exe_tx.send(ExecutorMessage::Stop {}).unwrap();
|
exe_tx.send(ExecutorMessage::Stop {}).unwrap();
|
||||||
exe_handle.await.unwrap();
|
exe_handle.await.unwrap();
|
||||||
|
|||||||
+20
-3
@@ -93,8 +93,25 @@ async fn get_state(state: web::Data<AppState>) -> impl Responder {
|
|||||||
let (response, rx) = oneshot::channel();
|
let (response, rx) = oneshot::channel();
|
||||||
|
|
||||||
state
|
state
|
||||||
.storage_tx
|
.runner_tx
|
||||||
.send(StorageMessage::LoadState { response })
|
.send(RunnerMessage::GetState { response })
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
match rx.await {
|
||||||
|
Ok(world) => HttpResponse::Ok().json(world),
|
||||||
|
Err(error) => HttpResponse::BadRequest().json(SimpleError {
|
||||||
|
error: format!("{:?}", error),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn timeline(span: web::Query<Interval>, state: web::Data<AppState>) -> impl Responder {
|
||||||
|
let interval = span.into_inner();
|
||||||
|
|
||||||
|
let (response, rx) = oneshot::channel();
|
||||||
|
state
|
||||||
|
.runner_tx
|
||||||
|
.send(RunnerMessage::GetResourceStateDetails { interval, response })
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
match rx.await {
|
match rx.await {
|
||||||
@@ -191,7 +208,7 @@ async fn main() -> std::io::Result<()> {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let runner_handle = tokio::spawn(async move {
|
let runner_handle = tokio::spawn(async move {
|
||||||
runner.run().await;
|
runner.run(true).await;
|
||||||
});
|
});
|
||||||
|
|
||||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
pub use crate::calendar::Calendar;
|
pub use crate::calendar::Calendar;
|
||||||
pub use crate::executors::*;
|
pub use crate::executors::*;
|
||||||
|
pub use crate::interval::Interval;
|
||||||
pub use crate::runner::{Runner, RunnerMessage};
|
pub use crate::runner::{Runner, RunnerMessage};
|
||||||
pub use crate::storage::*;
|
pub use crate::storage::*;
|
||||||
pub use crate::task::{TaskDefinition, TaskResources};
|
pub use crate::task::{TaskDefinition, TaskResources};
|
||||||
|
|||||||
+110
-17
@@ -30,8 +30,20 @@ pub struct Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct RunnerState {
|
||||||
|
coverage: ResourceInterval,
|
||||||
|
current: ResourceInterval,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Eventually we want to coerce the data into this format for timelines-chart
|
||||||
|
// Resource (group) -> Task (label) -> data [ { "timeRange": [date,date], "val": state } ]
|
||||||
|
pub type ResourceStateDetails =
|
||||||
|
HashMap<Resource, HashMap<String, Vec<(DateTime<Utc>, DateTime<Utc>, ActionState)>>>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum RunnerMessage {
|
pub enum RunnerMessage {
|
||||||
Tick,
|
Tick,
|
||||||
|
PollMessages,
|
||||||
ActionCompleted {
|
ActionCompleted {
|
||||||
action_id: usize,
|
action_id: usize,
|
||||||
succeeded: bool,
|
succeeded: bool,
|
||||||
@@ -50,6 +62,13 @@ pub enum RunnerMessage {
|
|||||||
resources: HashSet<String>,
|
resources: HashSet<String>,
|
||||||
interval: Interval,
|
interval: Interval,
|
||||||
},
|
},
|
||||||
|
GetState {
|
||||||
|
response: oneshot::Sender<RunnerState>,
|
||||||
|
},
|
||||||
|
GetResourceStateDetails {
|
||||||
|
interval: Interval,
|
||||||
|
response: oneshot::Sender<ResourceStateDetails>,
|
||||||
|
},
|
||||||
Stop,
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,14 +293,13 @@ impl Runner {
|
|||||||
storage,
|
storage,
|
||||||
};
|
};
|
||||||
|
|
||||||
runner.tick();
|
runner.update_target();
|
||||||
runner.queue_actions();
|
|
||||||
|
|
||||||
Ok(runner)
|
Ok(runner)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a new target state and generate any required actions
|
// Generate a new target state and generate any required actions
|
||||||
pub fn tick(&mut self) {
|
pub fn update_target(&mut self) {
|
||||||
let new_target = self.tasks.get_state(Utc::now() + Duration::days(1));
|
let new_target = self.tasks.get_state(Utc::now() + Duration::days(1));
|
||||||
let new_required = new_target.difference(&self.target);
|
let new_required = new_target.difference(&self.target);
|
||||||
let mut new_actions =
|
let mut new_actions =
|
||||||
@@ -310,16 +328,7 @@ impl Runner {
|
|||||||
self.actions.extend(new_actions);
|
self.actions.extend(new_actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(&mut self) {
|
fn tick(&mut self) {
|
||||||
self.events
|
|
||||||
.push(delayed_event(Duration::seconds(1), RunnerMessage::Tick));
|
|
||||||
|
|
||||||
// Need to incorporate the ability to receive messages
|
|
||||||
//
|
|
||||||
// Loop until the current state matches the end state
|
|
||||||
while !self.is_done() {
|
|
||||||
match self.events.next().await {
|
|
||||||
Some(Ok(RunnerMessage::Tick)) => {
|
|
||||||
debug!("Tick");
|
debug!("Tick");
|
||||||
// Enqueue new messages
|
// Enqueue new messages
|
||||||
while let Ok(msg) = self.messages.try_recv() {
|
while let Ok(msg) = self.messages.try_recv() {
|
||||||
@@ -337,8 +346,90 @@ impl Runner {
|
|||||||
// Perform maintenance
|
// Perform maintenance
|
||||||
self.queue_actions();
|
self.queue_actions();
|
||||||
|
|
||||||
self.events
|
self.events.push(delayed_event(
|
||||||
.push(delayed_event(Duration::seconds(5), RunnerMessage::Tick));
|
Duration::milliseconds(250),
|
||||||
|
RunnerMessage::Tick,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll_messages(&mut self) {
|
||||||
|
while let Ok(msg) = self.messages.try_recv() {
|
||||||
|
self.events.push(delayed_event(Duration::seconds(0), msg));
|
||||||
|
}
|
||||||
|
self.events.push(delayed_event(
|
||||||
|
Duration::milliseconds(10),
|
||||||
|
RunnerMessage::PollMessages,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_resource_state_details(
|
||||||
|
&self,
|
||||||
|
interval: Interval,
|
||||||
|
response: oneshot::Sender<ResourceStateDetails>,
|
||||||
|
) {
|
||||||
|
// HashMap<Resource, HashMap<String, Vec<(DateTime<Utc>, DateTime<Utc>, ActionState)>>>;
|
||||||
|
let mut res : ResourceStateDetails = HashMap::new();
|
||||||
|
|
||||||
|
let all_resources : HashSet<Resource> = self.tasks.iter().fold(HashSet::new(), |mut acc, t| {
|
||||||
|
acc.extend(t.provides.clone());
|
||||||
|
acc
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build out the hash
|
||||||
|
for resource in all_resources {
|
||||||
|
let mut res_ints = HashMap::new();
|
||||||
|
for task in self.tasks.iter() {
|
||||||
|
if task.provides.contains(&resource) {
|
||||||
|
res_ints.insert(task.name.clone(), Vec::new());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.insert(resource.clone(), res_ints);
|
||||||
|
}
|
||||||
|
|
||||||
|
let actions = self
|
||||||
|
.actions
|
||||||
|
.iter()
|
||||||
|
.filter(|x| interval.is_contiguous(x.interval))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
|
||||||
|
for action in actions {
|
||||||
|
let task = &self.tasks[action.task];
|
||||||
|
for resource in task.provides {
|
||||||
|
res.entry(resource.clone()).or_insert(HashMap::new()).entry(task.name).or_insert(Hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for task in &self.tasks {
|
||||||
|
for resource in &task.provides {}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.send(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn run(&mut self, mut stay_up: bool) {
|
||||||
|
self.tick();
|
||||||
|
self.poll_messages();
|
||||||
|
|
||||||
|
// Loop until the current state matches the end state
|
||||||
|
while stay_up || !self.is_done() {
|
||||||
|
match self.events.next().await {
|
||||||
|
Some(Ok(RunnerMessage::GetState { response })) => {
|
||||||
|
response
|
||||||
|
.send(RunnerState {
|
||||||
|
current: self.current.clone(),
|
||||||
|
coverage: self.end_state.clone(),
|
||||||
|
})
|
||||||
|
.unwrap_or(());
|
||||||
|
}
|
||||||
|
Some(Ok(RunnerMessage::PollMessages)) => {
|
||||||
|
self.poll_messages();
|
||||||
|
}
|
||||||
|
Some(Ok(RunnerMessage::Tick)) => {
|
||||||
|
self.tick();
|
||||||
|
}
|
||||||
|
Some(Ok(RunnerMessage::GetResourceStateDetails { interval, response })) => {
|
||||||
|
self.get_resource_state_details(interval, response);
|
||||||
}
|
}
|
||||||
Some(Ok(RunnerMessage::ForceUp {
|
Some(Ok(RunnerMessage::ForceUp {
|
||||||
resources,
|
resources,
|
||||||
@@ -386,6 +477,7 @@ impl Runner {
|
|||||||
}
|
}
|
||||||
Some(Ok(RunnerMessage::Stop)) => {
|
Some(Ok(RunnerMessage::Stop)) => {
|
||||||
info!("Stopping");
|
info!("Stopping");
|
||||||
|
stay_up = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Some(Ok(RunnerMessage::RetryAction { action_id })) => {
|
Some(Ok(RunnerMessage::RetryAction { action_id })) => {
|
||||||
@@ -410,8 +502,8 @@ impl Runner {
|
|||||||
|
|
||||||
fn complete_task(&mut self, action_id: usize, succeeded: bool) {
|
fn complete_task(&mut self, action_id: usize, succeeded: bool) {
|
||||||
info!("Completing action {}", action_id);
|
info!("Completing action {}", action_id);
|
||||||
if succeeded {
|
|
||||||
let action = &mut self.actions[action_id];
|
let action = &mut self.actions[action_id];
|
||||||
|
if succeeded {
|
||||||
let task = self.tasks.get(action.task).unwrap();
|
let task = self.tasks.get(action.task).unwrap();
|
||||||
action.state = ActionState::Completed;
|
action.state = ActionState::Completed;
|
||||||
for res in &task.provides {
|
for res in &task.provides {
|
||||||
@@ -423,6 +515,7 @@ impl Runner {
|
|||||||
self.store_state();
|
self.store_state();
|
||||||
self.queue_actions();
|
self.queue_actions();
|
||||||
} else {
|
} else {
|
||||||
|
action.state = ActionState::Errored;
|
||||||
self.events.push(delayed_event(
|
self.events.push(delayed_event(
|
||||||
Duration::seconds(30),
|
Duration::seconds(30),
|
||||||
RunnerMessage::RetryAction { action_id },
|
RunnerMessage::RetryAction { action_id },
|
||||||
@@ -567,7 +660,7 @@ mod tests {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
runner.run().await;
|
runner.run(false).await;
|
||||||
|
|
||||||
tx.send(ExecutorMessage::Stop {}).unwrap();
|
tx.send(ExecutorMessage::Stop {}).unwrap();
|
||||||
executor.await.unwrap();
|
executor.await.unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user