Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

editoast: extract all the STDCM log logic into a function #9947

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions editoast/editoast_models/src/tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,21 @@ diesel::table! {
}
}

diesel::table! {
use diesel::sql_types::*;
use postgis_diesel::sql_types::*;

stdcm_logs (id) {
id -> Int8,
#[max_length = 32]
trace_id -> Varchar,
request -> Jsonb,
response -> Jsonb,
created -> Timestamptz,
user_id -> Nullable<Int8>,
}
}

diesel::table! {
use diesel::sql_types::*;
use postgis_diesel::sql_types::*;
Expand Down Expand Up @@ -799,6 +814,7 @@ diesel::joinable!(search_project -> project (id));
diesel::joinable!(search_scenario -> scenario (id));
diesel::joinable!(search_signal -> infra_object_signal (id));
diesel::joinable!(search_study -> study (id));
diesel::joinable!(stdcm_logs -> authn_user (user_id));
diesel::joinable!(stdcm_search_environment -> electrical_profile_set (electrical_profile_set_id));
diesel::joinable!(stdcm_search_environment -> infra (infra_id));
diesel::joinable!(stdcm_search_environment -> temporary_speed_limit_group (temporary_speed_limit_group_id));
Expand Down Expand Up @@ -852,6 +868,7 @@ diesel::allow_tables_to_appear_in_same_query!(
search_signal,
search_study,
search_track,
stdcm_logs,
stdcm_search_environment,
study,
temporary_speed_limit,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE stdcm_logs;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE TABLE stdcm_logs (
id int8 PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
trace_id VARCHAR(32) UNIQUE NOT NULL,
request jsonb NOT NULL,
response jsonb NOT NULL,
created timestamptz NOT NULL DEFAULT NOW(),
user_id bigint REFERENCES authn_user ON DELETE CASCADE
);
64 changes: 64 additions & 0 deletions editoast/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8621,6 +8621,45 @@ components:
type: integer
format: int64
nullable: true
Response:
oneOf:
- type: object
required:
- simulation
- path
- departure_time
- status
properties:
departure_time:
type: string
format: date-time
path:
$ref: '#/components/schemas/PathfindingResultSuccess'
simulation:
$ref: '#/components/schemas/SimulationResponse'
status:
type: string
enum:
- success
- type: object
required:
- status
properties:
status:
type: string
enum:
- path_not_found
- type: object
required:
- error
- status
properties:
error:
$ref: '#/components/schemas/SimulationResponse'
status:
type: string
enum:
- preprocessing_simulation_error
RjsPowerRestrictionRange:
type: object
description: A range along the train path where a power restriction is applied.
Expand Down Expand Up @@ -10232,6 +10271,31 @@ components:
type: array
items:
$ref: '#/components/schemas/RangeAllowance'
StdcmLog:
type: object
required:
- id
- trace_id
- request
- response
- created
properties:
created:
type: string
format: date-time
id:
type: integer
format: int64
request:
$ref: '#/components/schemas/Request'
response:
$ref: '#/components/schemas/Response'
trace_id:
type: string
user_id:
type: integer
format: int64
nullable: true
StdcmSearchEnvironment:
type: object
required:
Expand Down
2 changes: 1 addition & 1 deletion editoast/src/core/conflict_detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub struct ConflictDetectionRequest {
pub work_schedules: Option<WorkSchedulesRequest>,
}

#[derive(Debug, Clone, Serialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrainRequirements {
pub start_time: DateTime<Utc>,
pub spacing_requirements: Vec<SpacingRequirement>,
Expand Down
1 change: 1 addition & 0 deletions editoast/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ editoast_common::schemas! {
simulation::schemas(),
pathfinding::schemas(),
conflict_detection::schemas(),
stdcm::schemas(),
}

#[derive(Debug, Clone)]
Expand Down
2 changes: 1 addition & 1 deletion editoast/src/core/simulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ editoast_common::schemas! {
SimulationResponse,
}

#[derive(Debug, Serialize, Derivative)]
#[derive(Debug, Clone, Serialize, Deserialize, Derivative)]
#[derivative(Hash)]
pub struct PhysicsConsist {
pub effort_curves: EffortCurves,
Expand Down
16 changes: 10 additions & 6 deletions editoast/src/core/stdcm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ use super::simulation::SimulationResponse;
use crate::core::AsCoreRequest;
use crate::core::Json;

#[derive(Debug, Serialize)]
editoast_common::schemas! {
Response,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Request {
/// Infrastructure id
pub infra: i64,
Expand Down Expand Up @@ -61,7 +65,7 @@ pub struct Request {
pub temporary_speed_limits: Vec<TemporarySpeedLimit>,
}

#[derive(Debug, Serialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PathItem {
/// The track offsets of the path item
pub locations: Vec<TrackOffset>,
Expand All @@ -72,7 +76,7 @@ pub struct PathItem {
}

/// Contains the data of a step timing, when it is specified
#[derive(Debug, Serialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StepTimingData {
/// Time the train should arrive at this point
pub arrival_time: DateTime<Utc>,
Expand All @@ -83,7 +87,7 @@ pub struct StepTimingData {
}

/// Lighter description of a work schedule, with only the relevant information for core
#[derive(Debug, Serialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkSchedule {
/// Start time as a time delta from the stdcm start time in ms
pub start_time: u64,
Expand All @@ -94,7 +98,7 @@ pub struct WorkSchedule {
}

/// Lighter description of a work schedule with only the relevant information for core
#[derive(Debug, Serialize)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemporarySpeedLimit {
/// Speed limitation in m/s
pub speed_limit: f64,
Expand All @@ -114,7 +118,7 @@ pub struct UndirectedTrackRange {
pub end: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, ToSchema)]
#[serde(tag = "status", rename_all = "snake_case")]
// We accepted the difference of memory size taken by variants
// Since there is only on success and others are error cases
Expand Down
2 changes: 2 additions & 0 deletions editoast/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod fixtures;
pub mod infra;
pub mod infra_objects;
pub mod layers;
pub mod stdcm_log;
// We allow unused until models is moved to a separate crate
pub mod auth;
pub mod pagination;
Expand Down Expand Up @@ -41,6 +42,7 @@ editoast_common::schemas! {
infra::schemas(),
projects::schemas(),
rolling_stock_model::schemas(),
stdcm_log::schemas(),
}

#[cfg(test)]
Expand Down
66 changes: 66 additions & 0 deletions editoast/src/models/stdcm_log.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use chrono::DateTime;
use chrono::Utc;
use editoast_derive::Model;
use editoast_models::DbConnection;
use opentelemetry::trace::TraceContextExt;
use serde::Deserialize;
use serde::Serialize;
use tracing_opentelemetry::OpenTelemetrySpanExt;
use utoipa::ToSchema;

use crate::core::stdcm::Request;
use crate::core::stdcm::Response;
use crate::models::prelude::*;
use crate::views::Authentication;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A views import in models :/

Given how things are going, the authentication and authorization are likely to stay in views and in a dedicated crate. The models "crate" won't probably know about that layer. Wdyt about taking an Option<i64> instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, so agreed. I really quickly prototyped this solution (maybe I should have opened a draft). This is one thing to improve for sure.


editoast_common::schemas! {
StdcmLog,
}

#[derive(Clone, Debug, Serialize, Deserialize, Model, ToSchema)]
#[model(table = editoast_models::tables::stdcm_logs)]
#[model(gen(ops = c))]
pub struct StdcmLog {
pub id: i64,
pub trace_id: String,
#[model(json)]
pub request: Request,
#[model(json)]
pub response: Response,
pub created: DateTime<Utc>,
pub user_id: Option<i64>,
}

impl StdcmLog {
// We just don't await the creation of the log entry since we want
// the endpoint to return as soon as possible, and because failing
// to persist a log entry is not a very important error here.
Comment on lines +35 to +37
Copy link
Contributor

@leovalais leovalais Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this comment stay near the spawn? It mentions an "endpoint" and awaiting or not the return value is a decision for the caller.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.

pub async fn log(
auth: Authentication,
mut conn: DbConnection,
request: Request,
response: Response,
) {
let user_id = auth.authorizer().map_or_else(
|e| {
tracing::error!("Authorization failed: {e}. Unable to retrieve user ID.");
None
},
|auth| Some(auth.user_id()),
);
let trace_id = tracing::Span::current()
.context()
.span()
.span_context()
.trace_id();
let stdcm_log_changeset = StdcmLog::changeset()
.trace_id(trace_id.to_string())
.request(request)
.response(response.clone())
.user_id(user_id);
let _ = stdcm_log_changeset
.create(&mut conn)
.await
.map_err(|e| tracing::error!("Failed during log operation: {e}"));
}
}
Loading
Loading