1+ import asyncio
12import logging
2- import time
3- from threading import Event
43from typing import Callable , Iterator , List , Optional
54
65from isar .config .settings import settings
@@ -49,9 +48,7 @@ def should_upload_inspections(task: TASKS) -> bool:
4948 return task .status == TaskStatus .Successful and isinstance (task , InspectionTask )
5049
5150
52- def get_task_status (
53- signal_exit : Event ,
54- signal_mission_stopped : Event ,
51+ async def get_task_status (
5552 robot : RobotInterface ,
5653 task_id : str ,
5754) -> TaskStatus :
@@ -62,10 +59,8 @@ def get_task_status(
6259 while (
6360 request_status_failure_counter < settings .REQUEST_STATUS_FAILURE_COUNTER_LIMIT
6461 ):
65- if signal_exit .wait (0 ) or signal_mission_stopped .wait (0 ):
66- return TaskStatus .Cancelled
6762 if request_status_failure_counter > 0 :
68- time .sleep (settings .REQUEST_STATUS_COMMUNICATION_RECONNECT_DELAY )
63+ await asyncio .sleep (settings .REQUEST_STATUS_COMMUNICATION_RECONNECT_DELAY )
6964
7065 try :
7166 task_status = robot .task_status (task_id )
@@ -103,9 +98,7 @@ def get_task_status(
10398 )
10499
105100
106- def get_mission_status (
107- signal_exit : Event ,
108- signal_mission_stopped : Event ,
101+ async def get_mission_status (
109102 robot : RobotInterface ,
110103 mission_id : str ,
111104) -> MissionStatus :
@@ -116,10 +109,8 @@ def get_mission_status(
116109 while (
117110 request_status_failure_counter < settings .REQUEST_STATUS_FAILURE_COUNTER_LIMIT
118111 ):
119- if signal_exit .wait (0 ) or signal_mission_stopped .wait (0 ):
120- break
121112 if request_status_failure_counter > 0 :
122- time .sleep (settings .REQUEST_STATUS_COMMUNICATION_RECONNECT_DELAY )
113+ await asyncio .sleep (settings .REQUEST_STATUS_COMMUNICATION_RECONNECT_DELAY )
123114
124115 try :
125116 mission_status = robot .mission_status (mission_id )
@@ -188,10 +179,8 @@ def get_mission_status_based_on_task_status(tasks: List[TASKS]) -> MissionStatus
188179 return MissionStatus .Successful
189180
190181
191- def robot_monitor_mission (
182+ async def robot_monitor_mission (
192183 mission : Mission ,
193- signal_exit : Event ,
194- signal_mission_stopped : Event ,
195184 robot : RobotInterface ,
196185 request_inspection_upload : Callable [[InspectionTask ], None ],
197186 mqtt_publisher : MqttClientInterface ,
@@ -204,114 +193,109 @@ def robot_monitor_mission(
204193 current_task .status = TaskStatus .NotStarted # type: ignore
205194 current_mission_status = MissionStatus .NotStarted
206195
207- while True :
208- if signal_exit .wait (0 ):
209- return None
210- if signal_mission_stopped .wait (0 ):
211- if current_task is not None :
212- current_task .status = TaskStatus .Cancelled
213- publish_task_status (mqtt_publisher , current_task , mission .id )
214- publish_mission_status (
215- mqtt_publisher ,
216- mission .id ,
217- MissionStatus .Cancelled ,
218- ErrorMessage (
219- ErrorReason .RobotMissionStatusException , "Mission cancelled"
220- ),
221- )
222- return None
223-
224- if current_task :
225- new_task_status : TaskStatus | None = None
226- try :
227- new_task_status = get_task_status (
228- signal_exit , signal_mission_stopped , robot , current_task .id
229- )
230-
231- if current_task .status != new_task_status :
232- current_task .status = new_task_status
233- log_task_status (logger , current_task )
234- publish_task_status (mqtt_publisher , current_task , mission .id )
196+ try :
197+ while True :
198+ if current_task :
199+ new_task_status : TaskStatus | None = None
200+ try :
201+ new_task_status = await get_task_status (robot , current_task .id )
235202
236- if is_finished (new_task_status ):
237- if should_upload_inspections (current_task ):
238- request_inspection_upload (current_task ) # type: ignore
239- current_task = get_next_task (task_iterator )
240- if current_task is not None :
241- # This is not required, but does make reporting more responsive
242- current_task .status = TaskStatus .InProgress
203+ if current_task .status != new_task_status :
204+ current_task .status = new_task_status
243205 log_task_status (logger , current_task )
244206 publish_task_status (mqtt_publisher , current_task , mission .id )
245- except RobotTaskStatusException as e :
246- logger .error (
247- "Failed to collect task status. Error description: %s" ,
248- e .error_description ,
249- )
250- # Currently we only stop mission monitoring after failing to get mission status
251207
252- new_mission_status : MissionStatus
253- try :
254- new_mission_status = get_mission_status (
255- signal_exit , signal_mission_stopped , robot , mission .id
256- )
257- except RobotMissionStatusException as e :
258- logger .exception ("Failed to collect mission status" )
259- error_message = ErrorMessage (
260- error_reason = e .error_reason ,
261- error_description = e .error_description ,
262- )
263- if current_task :
264- current_task .status = TaskStatus .Failed
265- publish_task_status (mqtt_publisher , current_task , mission .id )
266- publish_mission_status (
267- mqtt_publisher ,
268- mission .id ,
269- MissionStatus .Failed ,
270- error_message ,
271- )
272- break
273-
274- if new_mission_status == MissionStatus .Cancelled or (
275- new_mission_status
276- not in [MissionStatus .NotStarted , MissionStatus .InProgress ]
277- and current_task is None # We wait for all task statuses
278- ):
279- if (
280- new_mission_status == MissionStatus .Cancelled
281- and current_task is not None
282- and current_task .status == TaskStatus .InProgress
283- ):
284- current_task .status = TaskStatus .Cancelled
285- publish_task_status (mqtt_publisher , current_task , mission .id )
286-
287- # Standardises final mission status report
288- new_mission_status = get_mission_status_based_on_task_status (mission .tasks )
289- if error_message is None and new_mission_status in [
290- MissionStatus .Failed ,
291- MissionStatus .Cancelled ,
292- ]:
208+ if is_finished (new_task_status ):
209+ if should_upload_inspections (current_task ):
210+ request_inspection_upload (current_task ) # type: ignore
211+ current_task = get_next_task (task_iterator )
212+ if current_task is not None :
213+ # This is not required, but does make reporting more responsive
214+ current_task .status = TaskStatus .InProgress
215+ log_task_status (logger , current_task )
216+ publish_task_status (
217+ mqtt_publisher , current_task , mission .id
218+ )
219+ except RobotTaskStatusException as e :
220+ logger .error (
221+ "Failed to collect task status. Error description: %s" ,
222+ e .error_description ,
223+ )
224+ # Currently we only stop mission monitoring after failing to get mission status
225+
226+ new_mission_status : MissionStatus
227+ try :
228+ new_mission_status = await get_mission_status (robot , mission .id )
229+ except RobotMissionStatusException as e :
230+ logger .exception ("Failed to collect mission status" )
293231 error_message = ErrorMessage (
294- error_reason = None ,
295- error_description = "The mission failed because all tasks in the mission failed" ,
232+ error_reason = e . error_reason ,
233+ error_description = e . error_description ,
296234 )
297- publish_mission_status (
298- mqtt_publisher ,
299- mission .id ,
300- new_mission_status ,
301- error_message ,
302- )
303- break
235+ if current_task :
236+ current_task .status = TaskStatus .Failed
237+ publish_task_status (mqtt_publisher , current_task , mission .id )
238+ publish_mission_status (
239+ mqtt_publisher ,
240+ mission .id ,
241+ MissionStatus .Failed ,
242+ error_message ,
243+ )
244+ break
304245
305- if new_mission_status != current_mission_status :
306- current_mission_status = new_mission_status
307- publish_mission_status (
308- mqtt_publisher ,
309- mission .id ,
310- current_mission_status ,
311- error_message ,
312- )
246+ if new_mission_status == MissionStatus .Cancelled or (
247+ new_mission_status
248+ not in [MissionStatus .NotStarted , MissionStatus .InProgress ]
249+ and current_task is None # We wait for all task statuses
250+ ):
251+ if (
252+ new_mission_status == MissionStatus .Cancelled
253+ and current_task is not None
254+ and current_task .status == TaskStatus .InProgress
255+ ):
256+ current_task .status = TaskStatus .Cancelled
257+ publish_task_status (mqtt_publisher , current_task , mission .id )
313258
314- time .sleep (settings .FSM_SLEEP_TIME )
259+ # Standardises final mission status report
260+ new_mission_status = get_mission_status_based_on_task_status (
261+ mission .tasks
262+ )
263+ if error_message is None and new_mission_status in [
264+ MissionStatus .Failed ,
265+ MissionStatus .Cancelled ,
266+ ]:
267+ error_message = ErrorMessage (
268+ error_reason = None ,
269+ error_description = "The mission failed because all tasks in the mission failed" ,
270+ )
271+ publish_mission_status (
272+ mqtt_publisher ,
273+ mission .id ,
274+ new_mission_status ,
275+ error_message ,
276+ )
277+ break
278+
279+ if new_mission_status != current_mission_status :
280+ current_mission_status = new_mission_status
281+ publish_mission_status (
282+ mqtt_publisher ,
283+ mission .id ,
284+ current_mission_status ,
285+ error_message ,
286+ )
315287
316- logger .info ("Stopped monitoring mission" )
317- return error_message
288+ await asyncio .sleep (settings .FSM_SLEEP_TIME )
289+ logger .info ("Stopped monitoring mission" )
290+ return error_message
291+ except asyncio .CancelledError :
292+ if current_task is not None :
293+ current_task .status = TaskStatus .Cancelled
294+ publish_task_status (mqtt_publisher , current_task , mission .id )
295+ publish_mission_status (
296+ mqtt_publisher ,
297+ mission .id ,
298+ MissionStatus .Cancelled ,
299+ ErrorMessage (ErrorReason .RobotMissionStatusException , "Mission cancelled" ),
300+ )
301+ return None
0 commit comments