Skip to content
This repository has been archived by the owner on Aug 3, 2024. It is now read-only.

Commit

Permalink
tweaked blueprint scheduling algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
dvalnn committed May 29, 2024
1 parent ba1f270 commit 26695a2
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 62 deletions.
48 changes: 8 additions & 40 deletions src/scheduler/handlers/blueprint_handler.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use crate::{
db_api::{Item, Recipe},
scheduler::TIME_IN_DAY,
};
use crate::db_api::{Item, Recipe};

use super::item_handler::{self};

Expand All @@ -25,49 +22,20 @@ impl ItemBlueprint {
Ok(())
}

pub fn schedule(
&mut self,
due_date: i32,
current_date: i32,
) -> anyhow::Result<i32> {
let mut schedule_day = due_date;
let mut duration_acc = 0;

// walk back from the due date and find the
// last day that can accommodate each step in
// the process
for step in self.process.iter_mut() {
duration_acc += step.recipe.operation_time;
if duration_acc > TIME_IN_DAY {
schedule_day -= 1;
duration_acc = 0;
}

if schedule_day < current_date {
return Err(anyhow::anyhow!(
"Cannot schedule item, due date is in the past"
));
}

step.transf.set_date(schedule_day);

tracing::debug!(
"Scheduled transformation {:?} for day {}",
step.transf,
schedule_day
);
}

Ok(schedule_day)
pub fn set_start(&mut self, starting_date: i64) {
self.process
.last_mut()
.expect("empty process")
.transf
.set_date(starting_date as i32);
}

pub fn generate(
item: Item,
full_recipe: &[Recipe],
) -> anyhow::Result<ItemBlueprint> {
// for each item generate its components and
// transformations. Then schedule everything
// and update the item status to "Scheduled"
// transformations.
let process =
match item_handler::describe_process(full_recipe, item.clone()) {
Ok(proc) => proc,
Expand Down
56 changes: 34 additions & 22 deletions src/scheduler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,41 +48,53 @@ impl Scheduler {
let current_date = {
let mut con = pool.acquire().await?;
db_api::get_date(&mut con).await?
};
} as i64;
// earliest start is the next day so that materials can be prepared
let earliest_start = current_date + 1;

let blueprints = order_items
let mut blueprints = order_items
.iter()
.filter_map(|item| {
let mut bp = match ItemBlueprint::generate(
(*item).clone(),
&full_recipe,
) {
Ok(bp) => bp,
Err(e) => {
tracing::error!("{:?}", e);
return None;
}
};

match bp.schedule(order.due_date(), current_date as i32) {
Ok(_) => Some(bp),
match ItemBlueprint::generate((*item).clone(), &full_recipe) {
Ok(bp) => Some(bp),
Err(e) => {
tracing::error!("{:?}", e);
None
}
}
})
.collect::<Vec<_>>();

if blueprints.len() < order.quantity() as usize {
anyhow::bail!(
"Cannot fullfill order {:?}, can only schedule {:?}/{:?} parts",
order.id(),
blueprints.len(),
order.quantity()
assert_eq!(order_items.len(), blueprints.len());

//TODO: schedule the blueprints for production taking into account
//maximum factory parallelism capacity
let bp_time: i64 = full_recipe.iter().map(|r| r.operation_time).sum();

//TODO: make these constants config parameteres
//
// Assume that the factory can handle 3 blueprints in parallel at most
const PARALLELISM_CAPACITY: i64 = 3;
// assume a % of the needed time is spent on logistics instead of production
const LOGISTICS_TIME_FACTOR: i64 = 25;

// the last day that the order can be completed in order to be able to
// be delivered on time
let completion_date = order.due_date() as i64 - 1;
let bp_time = bp_time + bp_time * LOGISTICS_TIME_FACTOR / 100;
let total_time = bp_time * order.quantity() as i64;
let days_needed = total_time / (TIME_IN_DAY * PARALLELISM_CAPACITY);
if days_needed > completion_date - earliest_start {
tracing::warn!(
"Order {} cannot be completed on time, not enough capacity",
order.id()
);
}

let starting_date = earliest_start.max(completion_date - days_needed);
blueprints
.iter_mut()
.for_each(|bp| bp.set_start(starting_date));

let mut tx = pool.begin().await?;
for mut bp in blueprints {
bp.insert_to_db(&mut tx).await?;
Expand Down

0 comments on commit 26695a2

Please sign in to comment.