@@ -51,24 +51,28 @@ async def create_execution_stream(self, execution_id: str, user_id: str) -> Asyn
5151
5252 shutdown_event = await self .shutdown_manager .register_connection (execution_id , connection_id )
5353 if shutdown_event is None :
54- yield self ._format_sse_event (SSEExecutionEventData (
55- event_type = "error" ,
56- execution_id = execution_id ,
57- timestamp = datetime .now (timezone .utc ).isoformat (),
58- error = "Server is shutting down" ,
59- ))
54+ yield self ._format_sse_event (
55+ SSEExecutionEventData (
56+ event_type = "error" ,
57+ execution_id = execution_id ,
58+ timestamp = datetime .now (timezone .utc ).isoformat (),
59+ error = "Server is shutting down" ,
60+ )
61+ )
6062 return
6163
6264 subscription = None
6365 try :
6466 # Start opening subscription concurrently, then yield handshake
6567 sub_task = asyncio .create_task (self .sse_bus .open_subscription (execution_id ))
66- yield self ._format_sse_event (SSEExecutionEventData (
67- event_type = "connected" ,
68- execution_id = execution_id ,
69- timestamp = datetime .now (timezone .utc ).isoformat (),
70- connection_id = connection_id ,
71- ))
68+ yield self ._format_sse_event (
69+ SSEExecutionEventData (
70+ event_type = "connected" ,
71+ execution_id = execution_id ,
72+ timestamp = datetime .now (timezone .utc ).isoformat (),
73+ connection_id = connection_id ,
74+ )
75+ )
7276
7377 # Complete Redis subscription after handshake
7478 logger .info (f"Opening Redis subscription for execution { execution_id } " )
@@ -77,12 +81,14 @@ async def create_execution_stream(self, execution_id: str, user_id: str) -> Asyn
7781
7882 initial_status = await self .repository .get_execution_status (execution_id )
7983 if initial_status :
80- yield self ._format_sse_event (SSEExecutionEventData (
81- event_type = "status" ,
82- execution_id = initial_status .execution_id ,
83- timestamp = initial_status .timestamp ,
84- status = initial_status .status ,
85- ))
84+ yield self ._format_sse_event (
85+ SSEExecutionEventData (
86+ event_type = "status" ,
87+ execution_id = initial_status .execution_id ,
88+ timestamp = initial_status .timestamp ,
89+ status = initial_status .status ,
90+ )
91+ )
8692 self .metrics .record_sse_message_sent ("executions" , "status" )
8793
8894 async for event_data in self ._stream_events_redis (
@@ -109,26 +115,30 @@ async def _stream_events_redis(
109115 last_heartbeat = datetime .now (timezone .utc )
110116 while True :
111117 if shutdown_event .is_set ():
112- yield self ._format_sse_event (SSEExecutionEventData (
113- event_type = "shutdown" ,
114- execution_id = execution_id ,
115- timestamp = datetime .now (timezone .utc ).isoformat (),
116- message = "Server is shutting down" ,
117- grace_period = 30 ,
118- ))
118+ yield self ._format_sse_event (
119+ SSEExecutionEventData (
120+ event_type = "shutdown" ,
121+ execution_id = execution_id ,
122+ timestamp = datetime .now (timezone .utc ).isoformat (),
123+ message = "Server is shutting down" ,
124+ grace_period = 30 ,
125+ )
126+ )
119127 break
120128
121129 now = datetime .now (timezone .utc )
122130 if include_heartbeat and (now - last_heartbeat ).total_seconds () >= self .heartbeat_interval :
123- yield self ._format_sse_event (SSEExecutionEventData (
124- event_type = "heartbeat" ,
125- execution_id = execution_id ,
126- timestamp = now .isoformat (),
127- message = "SSE connection active" ,
128- ))
131+ yield self ._format_sse_event (
132+ SSEExecutionEventData (
133+ event_type = "heartbeat" ,
134+ execution_id = execution_id ,
135+ timestamp = now .isoformat (),
136+ message = "SSE connection active" ,
137+ )
138+ )
129139 last_heartbeat = now
130140
131- msg : RedisSSEMessage | None = await subscription .get (RedisSSEMessage , timeout = 0.5 )
141+ msg : RedisSSEMessage | None = await subscription .get (RedisSSEMessage )
132142 if not msg :
133143 continue
134144
@@ -145,36 +155,38 @@ async def _stream_events_redis(
145155 # Ignore malformed messages
146156 continue
147157
148- async def _build_sse_event_from_redis (
149- self , execution_id : str , msg : RedisSSEMessage
150- ) -> SSEExecutionEventData :
158+ async def _build_sse_event_from_redis (self , execution_id : str , msg : RedisSSEMessage ) -> SSEExecutionEventData :
151159 """Build typed SSE event from Redis message."""
152160 result : ExecutionResult | None = None
153161 if msg .event_type == EventType .RESULT_STORED :
154162 exec_domain = await self .repository .get_execution (execution_id )
155163 if exec_domain :
156164 result = ExecutionResult .model_validate (exec_domain )
157165
158- return SSEExecutionEventData .model_validate ({
159- ** msg .data ,
160- "event_type" : msg .event_type ,
161- "execution_id" : execution_id ,
162- "type" : msg .event_type ,
163- "result" : result ,
164- })
166+ return SSEExecutionEventData .model_validate (
167+ {
168+ ** msg .data ,
169+ "event_type" : msg .event_type ,
170+ "execution_id" : execution_id ,
171+ "type" : msg .event_type ,
172+ "result" : result ,
173+ }
174+ )
165175
166176 async def create_notification_stream (self , user_id : str ) -> AsyncGenerator [Dict [str , Any ], None ]:
167177 subscription = None
168178
169179 try :
170180 # Start opening subscription concurrently, then yield handshake
171181 sub_task = asyncio .create_task (self .sse_bus .open_notification_subscription (user_id ))
172- yield self ._format_notification_event (SSENotificationEventData (
173- event_type = "connected" ,
174- user_id = user_id ,
175- timestamp = datetime .now (timezone .utc ).isoformat (),
176- message = "Connected to notification stream" ,
177- ))
182+ yield self ._format_notification_event (
183+ SSENotificationEventData (
184+ event_type = "connected" ,
185+ user_id = user_id ,
186+ timestamp = datetime .now (timezone .utc ).isoformat (),
187+ message = "Connected to notification stream" ,
188+ )
189+ )
178190
179191 # Complete Redis subscription after handshake
180192 subscription = await sub_task
@@ -184,28 +196,32 @@ async def create_notification_stream(self, user_id: str) -> AsyncGenerator[Dict[
184196 # Heartbeat
185197 now = datetime .now (timezone .utc )
186198 if (now - last_heartbeat ).total_seconds () >= self .heartbeat_interval :
187- yield self ._format_notification_event (SSENotificationEventData (
188- event_type = "heartbeat" ,
189- user_id = user_id ,
190- timestamp = now .isoformat (),
191- message = "Notification stream active" ,
192- ))
199+ yield self ._format_notification_event (
200+ SSENotificationEventData (
201+ event_type = "heartbeat" ,
202+ user_id = user_id ,
203+ timestamp = now .isoformat (),
204+ message = "Notification stream active" ,
205+ )
206+ )
193207 last_heartbeat = now
194208
195209 # Forward notification messages as SSE data
196- redis_msg = await subscription .get (RedisNotificationMessage , timeout = 0.5 )
210+ redis_msg = await subscription .get (RedisNotificationMessage )
197211 if redis_msg :
198- yield self ._format_notification_event (SSENotificationEventData (
199- event_type = "notification" ,
200- notification_id = redis_msg .notification_id ,
201- severity = redis_msg .severity ,
202- status = redis_msg .status ,
203- tags = redis_msg .tags ,
204- subject = redis_msg .subject ,
205- body = redis_msg .body ,
206- action_url = redis_msg .action_url ,
207- created_at = redis_msg .created_at ,
208- ))
212+ yield self ._format_notification_event (
213+ SSENotificationEventData (
214+ event_type = "notification" ,
215+ notification_id = redis_msg .notification_id ,
216+ severity = redis_msg .severity ,
217+ status = redis_msg .status ,
218+ tags = redis_msg .tags ,
219+ subject = redis_msg .subject ,
220+ body = redis_msg .body ,
221+ action_url = redis_msg .action_url ,
222+ created_at = redis_msg .created_at ,
223+ )
224+ )
209225 finally :
210226 try :
211227 if subscription is not None :
0 commit comments