def _heartbeat_thread_job(self):
     """Thread that maintains inactive connections
     """
     # while not self._heartbeat_exit_event.is_set():
     while not self._heartbeat_exit_event:
         start = monotonic()
         with self._connection_lock.priority(0):
             if self._heartbeat_exit_event:
                 break
             recoverable_errors = (
                 self.connection.recoverable_channel_errors +
                 self.connection.recoverable_connection_errors)
             try:
                 try:
                     self._heartbeat_check()
                     try:
                         self.connection.drain_events(timeout=0.001)
                     except socket.timeout:
                         pass
                 except recoverable_errors as exc:
                     LOG.info("A recoverable connection/channel error occurred, "
                              "trying to reconnect: %s" % exc)
                     self.ensure_connection()
             except Exception:
                 LOG.warning("Unexpected error during heartbeart "
                             "thread processing, retrying...")
                 LOG.debug('Exception', exc_info=True)
             if self._heartbeat_exit_event:
                 break
         sleep_time = self._heartbeat_wait_timeout + start - monotonic()
         if sleep_time >= 0.0:
             eventlet.sleep(sleep_time)
Beispiel #2
0
 def start(self, timeout=5.0):
     """
     循环启动
     """
     timeout = float(timeout)
     self.running = True
     # 孵化心跳循环线程
     eventlet.spawn_n(self.heart_beat_loop)
     eventlet.sleep(0.1)
     overtime = monotonic() + timeout
     while True:
         if self.connection_pool._created_connections > 0:
             break
         if monotonic() > overtime:
             LOG.error('Redis connection pool init fail')
             self.running = False
             # 等待前面的绿色线程结束
             # eventlet.sleep(1.0)
             raise ConnectionError('redis connection pool empty over %1.2f seconds' % timeout)
         eventlet.sleep(timeout/5.0)
     # 孵化垃圾key删除循环
     eventlet.spawn_n(self.garbage_collector_loop)
Beispiel #3
0
 def heart_beat_loop(self):
     """
     心跳循环,用于外部domain线程
     PING命令不使用execute_command
     """
     pool = self.connection_pool
     heart_interval = float(self.heart_beat_over_time)*(float(self.heart_beat_over_time_max_count))
     heart_interval_s = heart_interval/1000
     error_connection_count = 0
     while True:
         if not self.running:
             break
         start_time = monotonic()*1000
         connection = None
         try:
             connection = pool.get_connection('PING')
             # 上次链接传包时间大于心跳间隔,发送PING命令
             if start_time - connection.last_beat > heart_interval:
                 connection.send_command("PING")
                 self.parse_response(connection, "PING")
             # 正常释放连接,链接重回可用连接池中
             pool.release(connection)
             if error_connection_count:
                 error_connection_count -= 1
         except (ConnectionError, TimeoutError) as e:
             LOG.warning('Heartbeat loop %(class)s: %(message)s' % {'class': e.__class__.__name__,
                                                                    'message': e.message})
             if connection:
                 # 踢出连接
                 pool.kickout(connection)
                 # 有链接还连续报错
                 # 多等待一段时间
                 if error_connection_count:
                     LOG.error('Heartbeat loop more then once, sleep more time')
                     eventlet.sleep(heart_interval_s*2)
             else:
                 # 分配不到链接,说明全部链接在忙或者无法生成链接(网络故障)
                 eventlet.sleep(heart_interval_s)
             error_connection_count += 1
         # 切换到其他绿色线程
         eventlet.sleep(heart_interval_s)
    def __init__(self, conf, purpose):
        # NOTE(viktors): Parse config options
        # driver_conf = conf.rabbit

        self.max_retries = conf.rabbit_max_retries
        self.interval_start = conf.rabbit_retry_interval
        self.interval_stepping = conf.rabbit_retry_backoff
        self.interval_max = conf.rabbit_interval_max
        self.login_method = conf.rabbit_login_method
        # self.fake_rabbit = driver_conf.fake_rabbit
        self.virtual_host = conf.rabbit_virtual_host
        self.rabbit_host = conf.rabbit_host
        # self.rabbit_hosts = driver_conf.rabbit_hosts
        self.rabbit_port = conf.rabbit_port
        self.rabbit_userid = conf.rabbit_userid
        self.rabbit_password = conf.rabbit_password
        self.rabbit_ha_queues = conf.rabbit_ha_queues
        self.rabbit_transient_queues_ttl = conf.rabbit_transient_queues_ttl
        self.rabbit_connect_timeout = conf.rabbit_connect_timeout
        self.rabbit_qos_prefetch_count = conf.rabbit_qos_prefetch_count
        self.heartbeat_timeout_threshold = conf.heartbeat_timeout_threshold
        self.heartbeat_rate = conf.heartbeat_rate
        self.kombu_reconnect_delay = conf.kombu_reconnect_delay
        self.amqp_durable_queues = conf.amqp_durable_queues
        self.amqp_auto_delete = conf.amqp_auto_delete
        self.rabbit_use_ssl = conf.rabbit_use_ssl
        self.kombu_missing_consumer_retry_timeout = \
            conf.kombu_missing_consumer_retry_timeout
        self.kombu_failover_strategy = conf.kombu_failover_strategy
        self.kombu_compression = conf.kombu_compression

        if self.rabbit_use_ssl:
            self.kombu_ssl_version = conf.kombu_ssl_version
            self.kombu_ssl_keyfile = conf.kombu_ssl_keyfile
            self.kombu_ssl_certfile = conf.kombu_ssl_certfile
            self.kombu_ssl_ca_certs = conf.kombu_ssl_ca_certs

        # Try forever?
        if self.max_retries <= 0:
            self.max_retries = None

        self._url = "amqp://%(username)s:%(password)s" \
                    "@%(host)s:%(port)s/%(vhost)s" % \
                    {'username': self.rabbit_userid, 'password': self.rabbit_password,
                     'host':self.rabbit_host, 'port':self.rabbit_port,
                     'vhost':self.virtual_host}

        self._initial_pid = os.getpid()
        self._consumers = {}
        self._new_tags = set()
        self._active_tags = {}
        self._tags = itertools.count(1)

        self._consume_loop_stopped = False
        self.channel = None
        self.purpose = purpose

        self.last_time = monotonic()
        if purpose == rpc_common.PURPOSE_SEND:
            self._connection_lock = PriorityLock()
            self._connection_lock.set_defalut_priority(1)
        else:
            self._connection_lock = DummyLock()

        # kombu set cloexec after socket connect
        # see function amqp.transport._AbstractTransport._connect
        self.connection = kombu.connection.Connection(
            self._url, ssl=self._fetch_ssl_params(),
            login_method=self.login_method,
            heartbeat=self.heartbeat_timeout_threshold,
            failover_strategy=self.kombu_failover_strategy,
            connect_timeout=self.rabbit_connect_timeout,
            transport_options={
                'confirm_publish': True,
                'client_properties': {'capabilities': {
                    'authentication_failure_close': True,
                    'connection.blocked': True,
                    'consumer_cancel_notify': True}},
                'on_blocked': self._on_connection_blocked,
                'on_unblocked': self._on_connection_unblocked,
            },
        )

        LOG.debug('Connecting to AMQP server on %(hostname)s:%(port)s' % self.connection.info())

        self._heartbeat_wait_timeout = (
            float(self.heartbeat_timeout_threshold) /
            float(self.heartbeat_rate) / 2.0)
        self._heartbeat_support_log_emitted = False

        # NOTE(sileht): just ensure the connection is setuped at startup
        self.ensure_connection()

        # NOTE(sileht): if purpose is PURPOSE_LISTEN
        # the consume code does the heartbeat stuff
        # we don't need a thread
        self._heartbeat_thread = None
        if purpose == rpc_common.PURPOSE_SEND:
            self._heartbeat_start()

        info  = self.connection.info()
        if isinstance(info, tuple):
            info = info[0]
        LOG.debug('Connected to AMQP server on %(hostname)s:%(port)s '
                  'via [%(transport)s] client' % info)
        # NOTE(sileht): value chosen according the best practice from kombu
        # http://kombu.readthedocs.org/en/latest/reference/kombu.common.html#kombu.common.eventloop
        # For heatbeat, we can set a bigger timeout, and check we receive the
        # heartbeat packets regulary
        if self._heartbeat_supported_and_enabled():
            self._poll_timeout = self._heartbeat_wait_timeout
        else:
            self._poll_timeout = 1
Beispiel #5
0
 def read_response(self):
     result = super(ConnectionEx, self).read_response()
     # 更新心跳时间
     self.last_beat = monotonic() * 1000
     return result
Beispiel #6
0
 def connect(self):
     if self._sock:
         return
     super(ConnectionEx, self).connect()
     self.last_beat = monotonic() * 1000