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 |