Enhance capacity management in DirectorWorker: Retrieve current capacity values directly from the database to prevent race conditions, calculate free capacity based on real-time data, and ensure production only occurs if sufficient storage is available. Update SQL query to check for adequate storage before returning production results.
This commit is contained in:
@@ -370,7 +370,38 @@ impl DirectorWorker {
|
|||||||
conn: &mut DbConnection,
|
conn: &mut DbConnection,
|
||||||
plan: &ProductionPlan,
|
plan: &ProductionPlan,
|
||||||
) -> Result<(), DbError> {
|
) -> Result<(), DbError> {
|
||||||
let free_capacity = Self::calc_free_capacity(plan);
|
// Hole aktuelle Kapazitätswerte direkt aus der DB, um Race Conditions zu vermeiden
|
||||||
|
let capacity_rows = conn.execute("get_branch_capacity", &[&plan.branch_id])?;
|
||||||
|
if capacity_rows.is_empty() {
|
||||||
|
eprintln!("[DirectorWorker] Keine Kapazitätsdaten für Branch {} gefunden", plan.branch_id);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let row = &capacity_rows[0];
|
||||||
|
let stock_size: i32 = row
|
||||||
|
.get("stock_size")
|
||||||
|
.and_then(|v| v.parse::<i32>().ok())
|
||||||
|
.unwrap_or(0);
|
||||||
|
let used_in_stock: i32 = row
|
||||||
|
.get("used_in_stock")
|
||||||
|
.and_then(|v| v.parse::<i32>().ok())
|
||||||
|
.unwrap_or(0);
|
||||||
|
let running_productions_quantity: i32 = row
|
||||||
|
.get("running_productions_quantity")
|
||||||
|
.and_then(|v| v.parse::<i32>().ok())
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
// Berechne freie Kapazität mit aktuellen Werten
|
||||||
|
let free_capacity = stock_size - used_in_stock - running_productions_quantity;
|
||||||
|
|
||||||
|
if free_capacity <= 0 {
|
||||||
|
eprintln!(
|
||||||
|
"[DirectorWorker] Keine Produktion gestartet: Kein freier Lagerplatz (stock_size={}, used={}, running_qty={})",
|
||||||
|
stock_size, used_in_stock, running_productions_quantity
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
let one_piece_cost = Self::calc_one_piece_cost(plan);
|
let one_piece_cost = Self::calc_one_piece_cost(plan);
|
||||||
let max_money_production = Self::calc_max_money_production(plan, one_piece_cost);
|
let max_money_production = Self::calc_max_money_production(plan, one_piece_cost);
|
||||||
|
|
||||||
@@ -437,9 +468,6 @@ impl DirectorWorker {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calc_free_capacity(plan: &ProductionPlan) -> i32 {
|
|
||||||
plan.stock_size - plan.used_in_stock - plan.running_productions_quantity
|
|
||||||
}
|
|
||||||
|
|
||||||
fn calc_one_piece_cost(plan: &ProductionPlan) -> f64 {
|
fn calc_one_piece_cost(plan: &ProductionPlan) -> f64 {
|
||||||
(plan.certificate * 6) as f64
|
(plan.certificate * 6) as f64
|
||||||
|
|||||||
@@ -1419,8 +1419,26 @@ pub const QUERY_GET_FINISHED_PRODUCTIONS: &str = r#"
|
|||||||
LEFT JOIN falukant_type.product_weather_effect pwe
|
LEFT JOIN falukant_type.product_weather_effect pwe
|
||||||
ON pwe.product_id = p.product_id
|
ON pwe.product_id = p.product_id
|
||||||
AND pwe.weather_type_id = w.weather_type_id
|
AND pwe.weather_type_id = w.weather_type_id
|
||||||
|
-- Prüfe, ob genug freier Lagerplatz vorhanden ist
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT
|
||||||
|
br2.id AS branch_id,
|
||||||
|
COALESCE(SUM(fds.quantity), 0) AS stock_size,
|
||||||
|
COALESCE(SUM(COALESCE(fdi.quantity, 0)), 0) AS used_in_stock,
|
||||||
|
COALESCE(SUM(COALESCE(fdp2.quantity, 0)), 0) AS running_productions_quantity
|
||||||
|
FROM falukant_data.branch br2
|
||||||
|
LEFT JOIN falukant_data.stock fds ON fds.branch_id = br2.id
|
||||||
|
LEFT JOIN falukant_data.inventory fdi ON fdi.stock_id = fds.id
|
||||||
|
LEFT JOIN falukant_data.production fdp2 ON fdp2.branch_id = br2.id
|
||||||
|
GROUP BY br2.id
|
||||||
|
) capacity ON capacity.branch_id = p.branch_id
|
||||||
-- Wetter-Effekte derzeit aus der Qualitätsberechnung entfernt
|
-- Wetter-Effekte derzeit aus der Qualitätsberechnung entfernt
|
||||||
WHERE p.start_timestamp + INTERVAL '1 minute' * pr.production_time <= NOW()
|
WHERE p.start_timestamp + INTERVAL '1 minute' * pr.production_time <= NOW()
|
||||||
|
-- Nur Produktionen zurückgeben, für die genug Lagerplatz vorhanden ist
|
||||||
|
-- running_productions_quantity enthält bereits p.quantity, daher prüfen wir:
|
||||||
|
-- (stock_size - used_in_stock - running_productions_quantity) >= 0
|
||||||
|
-- Das bedeutet: Nach Abzug aller laufenden Produktionen muss noch Platz vorhanden sein
|
||||||
|
AND (capacity.stock_size - capacity.used_in_stock - capacity.running_productions_quantity) >= 0
|
||||||
ORDER BY p.start_timestamp;
|
ORDER BY p.start_timestamp;
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user