def _state_loop(self): # TODO (NM) Arrange for _running to be set to false and stopping the katcp client # if this loop exits a is_connected = self.katcp_client.is_connected while self._running: self._logger.debug('Sending intial state') yield self._send_state(connected=is_connected(), synced=False, model_changed=False, data_synced=False) try: yield self.katcp_client.until_connected() self._logger.debug('Sending post-connected state') yield self._send_state(connected=is_connected(), synced=False, model_changed=False, data_synced=False) yield until_any(self.katcp_client.until_protocol(), self._disconnected.until_set()) if self.initial_inspection: if not is_connected(): continue model_changes = yield self.inspect() model_changed = bool(model_changes) synced = not model_changed yield self._send_state( connected=True, synced=False, model_changed=model_changed, data_synced=True, model_changes=model_changes) else: self.initial_inspection = True if not is_connected(): continue # We waited for the previous _send_state call (and user callbacks) to # complete before we change the state to synced=True yield self._send_state(connected=True, synced=True, model_changed=False, data_synced=True) yield until_any(self._interface_changed.until_set(), self._disconnected.until_set()) self._interface_changed.clear() continue # Next loop through should cause re-inspection and handle state updates except SyncError, e: retry_wait_time = self.reconnect_timeout self._logger.warn("Error syncing with device : {0!s} " "'Retrying in {1}s.".format(e, retry_wait_time)) yield katcp.core.until_later(retry_wait_time) # TODO (NM) Perhaps maintain count of unsuccessful attempts, and reconnect # if too many happen. Perhaps also integrate exponential-backoff stuff # here? Or outsource to a user-supplied class or callback? continue except Exception: retry_wait_time = self.reconnect_timeout self._logger.exception( 'Unhandled exception in client-sync loop. Triggering disconnect and ' 'Retrying in {}s.' .format(retry_wait_time)) self.katcp_client.disconnect() yield katcp.core.until_later(retry_wait_time) continue
def _state_loop(self): # TODO (NM) Arrange for _running to be set to false and stopping the katcp client # if this loop exits self.resync_delay = ExponentialRandomBackoff( self.initial_resync_timeout, self.max_resync_timeout) is_connected = self.katcp_client.is_connected last_sync_failed = False while self._running: self._logger.debug('{}: Sending initial state'.format( self.bind_address_string)) yield self._send_state(connected=is_connected(), synced=False, model_changed=False, data_synced=False) try: yield self.katcp_client.until_connected() self._logger.debug('{}: Sending post-connected state'.format( self.bind_address_string)) yield self._send_state(connected=is_connected(), synced=False, model_changed=False, data_synced=False) yield until_any(self.katcp_client.until_protocol(), self._disconnected.until_set()) # TODO NM 2016-10-21 The naming of this attribute is incredibly # confusing, we need to think about what "initial_inspection" is # and how it is supposed to be handled if self.initial_inspection: if not is_connected(): continue model_changes = yield self.inspect() model_changed = bool(model_changes) self._logger.debug('{}: Sending data-synced state'.format( self.bind_address_string)) yield self._send_state(connected=True, synced=False, model_changed=model_changed, data_synced=True, model_changes=model_changes) else: self.initial_inspection = True if not is_connected(): continue # TODO NM 2017-07-21 for CB-1466 (async dev handler) we need to # check if the device needs a re-sync after the state change # callback, since some proxy actions can result in the device # issuing an #interface-changed between _send_state() above and # here. # We waited for the previous _send_state call (and user callbacks) to # complete before we change the state to synced=True self._logger.debug('{}: Sending synced state'.format( self.bind_address_string)) yield self._send_state(connected=True, synced=True, model_changed=False, data_synced=True) if last_sync_failed: self._logger.warn( 'Succesfully resynced with {} after failure'.format( self.bind_address_string)) last_sync_failed = False yield until_any(self._interface_changed.until_set(), self._disconnected.until_set()) self._logger.debug( 'in _state_loop: interface_changed=%s,' ' is_connected=%s', self._interface_changed.is_set(), self._disconnected.is_set()) self._interface_changed.clear() continue # Next loop through should cause re-inspection and handle state updates except SyncError, e: last_sync_failed = True retry_wait_time = self.resync_delay.delay self.resync_delay.failed() self._logger.warn( "Error syncing with device {}: {!s} 'Retrying in {}s.". format(self.bind_address_string, e, retry_wait_time)) yield katcp.core.until_later(retry_wait_time) # TODO (NM) Perhaps maintain count of unsuccessful attempts, and reconnect # if too many happen. Perhaps also integrate exponential-backoff stuff # here? Or outsource to a user-supplied class or callback? continue except Exception: last_sync_failed = True retry_wait_time = self.resync_delay.delay self.resync_delay.failed() self._logger.exception( 'Unhandled exception in client-sync loop. Triggering disconnect and ' 'Retrying in {}s.'.format(retry_wait_time)) self.katcp_client.disconnect() yield katcp.core.until_later(retry_wait_time) continue
def _state_loop(self): # TODO (NM) Arrange for _running to be set to false and stopping the katcp client # if this loop exits self.resync_delay = ExponentialRandomBackoff( self.initial_resync_timeout, self.max_resync_timeout) is_connected = self.katcp_client.is_connected last_sync_failed = False while self._running: self._logger.debug('{}: Sending intial state' .format(self.bind_address_string)) yield self._send_state(connected=is_connected(), synced=False, model_changed=False, data_synced=False) try: yield self.katcp_client.until_connected() self._logger.debug('{}: Sending post-connected state' .format(self.bind_address_string)) yield self._send_state(connected=is_connected(), synced=False, model_changed=False, data_synced=False) yield until_any(self.katcp_client.until_protocol(), self._disconnected.until_set()) # TODO NM 2016-10-21 The naming of this attribute is incredibly # confusing, we need to think about what "initial_inspection" # how supposed to be handled if self.initial_inspection: if not is_connected(): continue model_changes = yield self.inspect() model_changed = bool(model_changes) self._logger.debug('{}: Sending data-synced state' .format(self.bind_address_string)) yield self._send_state( connected=True, synced=False, model_changed=model_changed, data_synced=True, model_changes=model_changes) else: self.initial_inspection = True if not is_connected(): continue # We waited for the previous _send_state call (and user callbacks) to # complete before we change the state to synced=True self._logger.debug('{}: Sending synced state' .format(self.bind_address_string)) yield self._send_state(connected=True, synced=True, model_changed=False, data_synced=True) if last_sync_failed: self._logger.warn( 'Succesfully resynced with {} after failure' .format(self.bind_address_string)) last_sync_failed = False yield until_any(self._interface_changed.until_set(), self._disconnected.until_set()) self._logger.debug('in _state_loop: interface_changed=%s,' ' is_connected=%s', self._interface_changed.is_set(), self._disconnected.is_set()) self._interface_changed.clear() continue # Next loop through should cause re-inspection and handle state updates except SyncError, e: last_sync_failed = True retry_wait_time = self.resync_delay.delay self.resync_delay.failed() self._logger.warn( "Error syncing with device {}: {!s} 'Retrying in {}s." .format( self.bind_address_string, e, retry_wait_time)) yield katcp.core.until_later(retry_wait_time) # TODO (NM) Perhaps maintain count of unsuccessful attempts, and reconnect # if too many happen. Perhaps also integrate exponential-backoff stuff # here? Or outsource to a user-supplied class or callback? continue except Exception: last_sync_failed = True retry_wait_time = self.resync_delay.delay self.resync_delay.failed() self._logger.exception( 'Unhandled exception in client-sync loop. Triggering disconnect and ' 'Retrying in {}s.' .format(retry_wait_time)) self.katcp_client.disconnect() yield katcp.core.until_later(retry_wait_time) continue