Skip to content

Commit f977f2f

Browse files
committed
Structure defined for the pydantic model representing Event to be injected
1 parent f57059b commit f977f2f

2 files changed

Lines changed: 104 additions & 0 deletions

File tree

src/asyncflow/config/constants.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,19 @@ class SystemEdges(StrEnum):
175175

176176
NETWORK_CONNECTION = "network_connection"
177177

178+
# ======================================================================
179+
# CONSTANTS FOR THE EVENT TO INJECT IN THE SIMULATION
180+
# ======================================================================
181+
182+
class EventDescription(StrEnum):
183+
"""Description for the events you may inject during the simulation"""
184+
185+
SERVER_UP = "server_up"
186+
SERVER_DOWN = "server_down"
187+
NETWORK_SPIKE_START = "network_spike_start"
188+
NETWORK_SPIKE_END = "network_spike_end"
189+
190+
178191
# ======================================================================
179192
# CONSTANTS FOR SAMPLED METRICS
180193
# ======================================================================
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""Pydantic model to inject event during the simulation"""
2+
3+
from typing import Literal
4+
5+
from pydantic import (
6+
BaseModel,
7+
ConfigDict,
8+
NonNegativeFloat,
9+
PositiveFloat,
10+
model_validator,
11+
)
12+
13+
from asyncflow.config.constants import EventDescription
14+
15+
# Event input schema:
16+
# - Each event has its own identifier (event_id) and references the affected
17+
# component via target_id.
18+
# - The event window is represented by two markers, Start and End.
19+
# - We constrain kind with Literal[...] over EventDescription (a StrEnum),
20+
# so Pydantic enforces allowed values automatically for both Start and End.
21+
# - Both marker models use ConfigDict(extra="forbid", frozen=True):
22+
# extra="forbid" rejects unknown fields (e.g., catches t_strat vs t_start);
23+
# frozen=True makes instances immutable at runtime for stability.
24+
25+
# Yaml example:
26+
# event_id: ev-1
27+
# target_id: srv-1
28+
# start: { kind: SERVER_DOWN, t_start: 120.0 }
29+
# end: { kind: SERVER_UP, t_end: 240.0 }
30+
31+
class Start(BaseModel):
32+
"""Start marker for an event window."""
33+
34+
model_config = ConfigDict(extra="forbid", frozen=True)
35+
36+
# Only "start" kinds allowed here
37+
kind: Literal[
38+
EventDescription.SERVER_DOWN,
39+
EventDescription.NETWORK_SPIKE_START,
40+
]
41+
t_start: NonNegativeFloat # seconds from simulation start
42+
43+
44+
class End(BaseModel):
45+
"""End marker for an event window."""
46+
47+
model_config = ConfigDict(extra="forbid", frozen=True)
48+
49+
# Only "end" kinds allowed here
50+
kind: Literal[
51+
EventDescription.SERVER_UP,
52+
EventDescription.NETWORK_SPIKE_END,
53+
]
54+
t_end: PositiveFloat # strictly > 0
55+
56+
class Event(BaseModel):
57+
"""Definition of the input structure to define an event in the simulation"""
58+
59+
event_id: str
60+
target_id: str
61+
start: Start
62+
end: End
63+
64+
@model_validator(mode="after") # type: ignore[arg-type]
65+
def ensure_start_end_compatibility(
66+
cls, # noqa: N805
67+
model: "Event",
68+
) -> "Event":
69+
"""
70+
Check the compatibility between Start and End both at level
71+
of time interval and kind
72+
"""
73+
# Ensure kind for Start and End are compatible
74+
start_to_end = {
75+
EventDescription.SERVER_DOWN: EventDescription.SERVER_UP,
76+
EventDescription.NETWORK_SPIKE_START: EventDescription.NETWORK_SPIKE_END,
77+
}
78+
79+
expected = start_to_end[model.start.kind]
80+
if model.end.kind != expected:
81+
msg = (f"The event {model.event_id} must have"
82+
f"as value of kind in end {expected}")
83+
raise ValueError(msg)
84+
85+
# Ensure the time sequence is well defined
86+
if model.start.t_start >= model.end.t_end:
87+
msg=(f"The starting time for the event {model.event_id}"
88+
"must be smaller than the ending time")
89+
raise ValueError(msg)
90+
91+

0 commit comments

Comments
 (0)