'Checks the presence of users that have timed out and updates as
appropriate.'

def _handle_timeouts(self):

    logger.info('Handling    presence    timeouts')
    now = self.clock.time_msec()
    try:
        with Measure(self.clock, 'presence_handle_timeouts'):
            users_to_check = set(self.wheel_timer.fetch(now))
            expired_process_ids = [process_id for (process_id, last_update) in self.external_process_last_updated_ms.items() if ((now - last_update) > EXTERNAL_PROCESS_EXPIRY)]
            for process_id in expired_process_ids:
                users_to_check.update(self.external_process_last_updated_ms.pop(process_id, ()))
                self.external_process_last_update.pop(process_id)
            states = [self.user_to_current_state.get(user_id, UserPresenceState.default(user_id)) for user_id in users_to_check]
            timers_fired_counter.inc_by(len(states))
            changes = handle_timeouts(states, is_mine_fn=self.is_mine_id, syncing_user_ids=self.get_currently_syncing_users(), now=now)
        preserve_fn(self._update_states)(changes)
    except:
        logger.exception('Exception    in    _handle_timeouts    loop')
