| 208 |
208 |
| 209 logger.debug('Result listener thread waiting for result') |
209 logger.debug('Result listener thread waiting for result') |
| 210 |
210 |
| 211 res=self.borg_instance.read_result() |
211 res=self.borg_instance.read_result() |
| 212 |
212 |
| 213 success=True |
213 errors=False |
| 214 |
214 |
| 215 logger.debug('Borg result: %s' % str(res)) |
215 logger.debug('Borg result: %s' % str(res)) |
| 216 |
216 |
| 217 if res==None: |
217 if res is None: |
| 218 success=False |
218 errors=True |
| 219 |
219 |
| 220 logger.debug('Waiting for borg subprocess to terminate in result thread') |
220 logger.debug('Waiting for borg subprocess to terminate in result thread') |
| 221 |
221 |
| 222 success=success and self.borg_instance.wait() |
222 errors=errors or not self.borg_instance.wait() |
| 223 |
223 |
| 224 logger.debug('Borg subprocess terminated (success: %s); terminating result listener thread' % str(success)) |
224 logger.debug('Borg subprocess terminated (errors: %s); terminating result listener thread' % str(errors)) |
| 225 |
225 |
| 226 self.thread_log.join() |
226 self.thread_log.join() |
| 227 |
227 |
| 228 with self.lock: |
228 with self.lock: |
| 229 if self.current_operation['operation']=='create': |
229 if self.current_operation['operation']=='create': |
| 230 self.lastrun_when=self.current_operation['when_monotonic'] |
230 self.lastrun_when=self.current_operation['when_monotonic'] |
| 231 self.lastrun_success=success |
231 self.lastrun_errors=errors |
| 232 self.thread_res=None |
232 self.thread_res=None |
| 233 self.thread_log=None |
233 self.thread_log=None |
| 234 self.borg_instance=None |
234 self.borg_instance=None |
| 235 self.current_operation=None |
235 self.current_operation=None |
| 236 self.__schedule_unlocked() |
236 self.__schedule_unlocked() |
| 292 else: |
292 else: |
| 293 raise NotImplementedError("Invalid operation '%s'" % op['operation']) |
293 raise NotImplementedError("Invalid operation '%s'" % op['operation']) |
| 294 except Exception as err: |
294 except Exception as err: |
| 295 logger.debug('Rescheduling after failure') |
295 logger.debug('Rescheduling after failure') |
| 296 self.lastrun_when=time.monotonic() |
296 self.lastrun_when=time.monotonic() |
| 297 self.lastrun_success=False |
297 self.lastrun_errors=True |
| 298 self.__schedule_unlocked() |
298 self.__schedule_unlocked() |
| 299 raise err |
299 raise err |
| 300 |
300 |
| 301 return True |
301 return True |
| 302 |
302 |
| 367 return None |
367 return None |
| 368 else: |
368 else: |
| 369 return {'operation': 'create', |
369 return {'operation': 'create', |
| 370 'detail': 'initial', |
370 'detail': 'initial', |
| 371 'when_monotonic': now+initial_interval} |
371 'when_monotonic': now+initial_interval} |
| 372 elif not self.lastrun_success: |
372 elif self.lastrun_errors: |
| 373 if self.retry_interval==0: |
373 if self.retry_interval==0: |
| 374 return None |
374 return None |
| 375 else: |
375 else: |
| 376 return {'operation': 'create', |
376 return {'operation': 'create', |
| 377 'detail': 'retry', |
377 'detail': 'retry', |
| 379 else: |
379 else: |
| 380 if self.backup_interval==0: |
380 if self.backup_interval==0: |
| 381 return None |
381 return None |
| 382 else: |
382 else: |
| 383 return {'operation': 'create', |
383 return {'operation': 'create', |
| 384 'detail': None, |
384 'detail': 'normal', |
| 385 'when_monotonic': self.lastrun_when+self.backup_interval} |
385 'when_monotonic': self.lastrun_when+self.backup_interval} |
| 386 |
386 |
| 387 def __schedule_unlocked(self): |
387 def __schedule_unlocked(self): |
| 388 if self.current_operation: |
388 if self.current_operation: |
| 389 return self.current_operation |
389 return self.current_operation |
| 411 res=self.__status_unlocked() |
411 res=self.__status_unlocked() |
| 412 return res[0] |
412 return res[0] |
| 413 |
413 |
| 414 def __status_unlocked(self): |
414 def __status_unlocked(self): |
| 415 callback=self.__status_update_callback |
415 callback=self.__status_update_callback |
| |
416 |
| 416 if self.current_operation: |
417 if self.current_operation: |
| 417 status=self.current_operation |
418 status=self.current_operation |
| 418 status['type']='current' |
419 status['type']='current' |
| 419 elif self.scheduled_operation: |
420 # Errors should be set by listeners |
| 420 status=self.scheduled_operation |
|
| 421 status['type']='scheduled' |
|
| 422 else: |
421 else: |
| 423 status={'type': 'nothing'} |
422 if self.scheduled_operation: |
| 424 |
423 status=self.scheduled_operation |
| 425 status['name']=self.name |
424 status['type']='scheduled' |
| |
425 else: |
| |
426 status={'type': 'nothing'} |
| |
427 |
| |
428 if self.lastrun_errors is not None: |
| |
429 status['errors']=self.lastrun_errors |
| |
430 |
| |
431 if 'detail' not in status: |
| |
432 status['detail']='NONE' |
| 426 |
433 |
| 427 if 'errors' not in status: |
434 if 'errors' not in status: |
| 428 status['errors']=False |
435 status['errors']=False |
| |
436 |
| |
437 status['name']=self.name |
| 429 |
438 |
| 430 if 'when_monotonic' in status: |
439 if 'when_monotonic' in status: |
| 431 status['when']=(status['when_monotonic'] |
440 status['when']=(status['when_monotonic'] |
| 432 -time.monotonic()+time.time()) |
441 -time.monotonic()+time.time()) |
| 433 |
442 |