Improve ProgramRunner task error handling
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				continuous-integration/drone/push Build is passing
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			This commit is contained in:
		
							parent
							
								
									9d5877106b
								
							
						
					
					
						commit
						d4e067a947
					
				| @ -1,5 +1,6 @@ | ||||
| use crate::model::{ProgramId, ProgramRef, Programs, Sections}; | ||||
| use crate::section_runner::{SectionEvent, SectionRunHandle, SectionRunner}; | ||||
| use eyre::WrapErr; | ||||
| use std::collections::VecDeque; | ||||
| use thiserror::Error; | ||||
| use tokio::{ | ||||
| @ -101,13 +102,13 @@ impl RunnerTask { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     async fn start_program_run(&mut self, run: &mut ProgRun) { | ||||
|     async fn start_program_run(&mut self, run: &mut ProgRun) -> eyre::Result<()> { | ||||
|         if run.state != RunState::Waiting { | ||||
|             warn!( | ||||
|                 program_id = run.program.id, | ||||
|                 "cannot run program which is already running" | ||||
|             ); | ||||
|             return; | ||||
|             return Ok(()); | ||||
|         } | ||||
|         run.sec_run_handles.reserve(run.program.sequence.len()); | ||||
|         for item in &run.program.sequence { | ||||
| @ -122,14 +123,11 @@ impl RunnerTask { | ||||
|                     continue; | ||||
|                 } | ||||
|             }; | ||||
|             let handle = match self.section_runner.queue_run(section, item.duration).await { | ||||
|                 Ok(handle) => handle, | ||||
|                 Err(_closed) => { | ||||
|                     error!("section runner channel closed"); | ||||
|                     self.running = false; | ||||
|                     return; | ||||
|                 } | ||||
|             }; | ||||
|             let handle = self | ||||
|                 .section_runner | ||||
|                 .queue_run(section, item.duration) | ||||
|                 .await | ||||
|                 .wrap_err("failed to queue section run")?; | ||||
|             run.sec_run_handles.push(handle); | ||||
|         } | ||||
|         run.state = RunState::Running; | ||||
| @ -141,31 +139,36 @@ impl RunnerTask { | ||||
|         } else { | ||||
|             debug!(program_id = run.program.id, "started running program"); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     async fn cancel_program_run(&mut self, run: &mut ProgRun) { | ||||
|     async fn cancel_program_run(&mut self, run: &mut ProgRun) -> eyre::Result<()> { | ||||
|         for handle in run.sec_run_handles.drain(..) { | ||||
|             if let Err(_closed) = self.section_runner.cancel_run(handle).await { | ||||
|                 error!("section runner channel closed"); | ||||
|                 self.running = false; | ||||
|                 return; | ||||
|             } | ||||
|             self.section_runner | ||||
|                 .cancel_run(handle) | ||||
|                 .await | ||||
|                 .wrap_err("failed to cancel section run")?; | ||||
|         } | ||||
|         debug!(program_id = run.program.id, "program run is cancelled"); | ||||
|         self.send_event(ProgramEvent::RunCancel(run.program.clone())); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     async fn process_queue(&mut self, run_queue: &mut RunQueue) { | ||||
|     async fn process_queue(&mut self, run_queue: &mut RunQueue) -> eyre::Result<()> { | ||||
|         while let Some(current_run) = run_queue.front_mut() { | ||||
|             let run_finished = match current_run.state { | ||||
|                 RunState::Waiting => { | ||||
|                     self.start_program_run(current_run).await; | ||||
|                     self.start_program_run(current_run) | ||||
|                         .await | ||||
|                         .wrap_err("failed to start program run")?; | ||||
|                     false | ||||
|                 } | ||||
|                 RunState::Running => false, | ||||
|                 RunState::Finished => true, | ||||
|                 RunState::Cancelled => { | ||||
|                     self.cancel_program_run(current_run).await; | ||||
|                     self.cancel_program_run(current_run) | ||||
|                         .await | ||||
|                         .wrap_err("failed to cancel program run")?; | ||||
|                     true | ||||
|                 } | ||||
|             }; | ||||
| @ -175,6 +178,7 @@ impl RunnerTask { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn handle_msg(&mut self, msg: Option<RunnerMsg>, run_queue: &mut RunQueue) { | ||||
| @ -239,22 +243,8 @@ impl RunnerTask { | ||||
|         &mut self, | ||||
|         sec_event: Result<SectionEvent, broadcast::RecvError>, | ||||
|         run_queue: &mut RunQueue, | ||||
|     ) { | ||||
|         let sec_event = match sec_event { | ||||
|             Ok(ev) => ev, | ||||
|             Err(broadcast::RecvError::Lagged(missed)) => { | ||||
|                 warn!( | ||||
|                     missed, | ||||
|                     "missed some section events, increase event channel size" | ||||
|                 ); | ||||
|                 return; | ||||
|             } | ||||
|             Err(broadcast::RecvError::Closed) => { | ||||
|                 error!("section events channel closed"); | ||||
|                 self.running = false; | ||||
|                 return; | ||||
|             } | ||||
|         }; | ||||
|     ) -> eyre::Result<()> { | ||||
|         let sec_event = sec_event.wrap_err("failed to receive section event")?; | ||||
|         #[allow(clippy::single_match)] | ||||
|         match sec_event { | ||||
|             SectionEvent::RunFinish(finished_run) => { | ||||
| @ -262,28 +252,39 @@ impl RunnerTask { | ||||
|             } | ||||
|             _ => {} | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     async fn start_impl(&mut self) -> eyre::Result<()> { | ||||
|         let mut sec_events = self | ||||
|             .section_runner | ||||
|             .subscribe() | ||||
|             .await | ||||
|             .wrap_err("could not subscribe to SectionRunner events")?; | ||||
| 
 | ||||
|         let mut run_queue: RunQueue = VecDeque::new(); | ||||
| 
 | ||||
|         while self.running { | ||||
|             self.process_queue(&mut run_queue) | ||||
|                 .await | ||||
|                 .wrap_err("error during queue processing")?; | ||||
|             tokio::select! { | ||||
|                 msg = self.msg_recv.recv() => self.handle_msg(msg, &mut run_queue), | ||||
|                 sec_event = sec_events.recv() => self.handle_sec_event(sec_event, &mut run_queue)?, | ||||
|                 // _ = &mut self.delay_future, if self.delay_future.is_some() => delay_done()
 | ||||
|             }; | ||||
|         } | ||||
| 
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     async fn start(mut self) { | ||||
|         let span = trace_span!("runner_task"); | ||||
|         let _enter = span.enter(); | ||||
| 
 | ||||
|         let mut sec_events = self | ||||
|             .section_runner | ||||
|             .subscribe() | ||||
|         self.start_impl() | ||||
|             .await | ||||
|             .expect("could not subscribe to SectionRunner events"); | ||||
| 
 | ||||
|         let mut run_queue: RunQueue = VecDeque::new(); | ||||
| 
 | ||||
|         while self.running { | ||||
|             self.process_queue(&mut run_queue).await; | ||||
|             tokio::select! { | ||||
|                 msg = self.msg_recv.recv() => self.handle_msg(msg, &mut run_queue), | ||||
|                 sec_event = sec_events.recv() => self.handle_sec_event(sec_event, &mut run_queue), | ||||
|                 // _ = &mut self.delay_future, if self.delay_future.is_some() => delay_done()
 | ||||
|             }; | ||||
|         } | ||||
|             .expect("error in ProgramRunner task"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user