Exemplo n.º 1
0
 def __log_receival_one_message(self, message):
     if self.__first_message_receival:
         logdebug(LOGGER, 'Handing over first message to rabbit thread...')
         self.__first_message_receival = False
     logtrace(LOGGER, 'Handing over one message over to the rabbit thread (%s)', message)
     log_every_x_times(LOGGER, self.__logcounter_received, self.__LOGFREQUENCY, 'Handing over one message over to the rabbit thread (no. %i).', self.__logcounter_received)
     self.__logcounter_received += 1
Exemplo n.º 2
0
 def __put_all_messages_into_queue_of_unsent_messages(self, messages):
     counter = 1
     for message in messages:
         logtrace(LOGGER, 'Adding message %i/%i to stack to be sent.',
                  counter, len(messages))
         counter += 1
         self.__put_one_message_into_queue_of_unsent_messages(message)
Exemplo n.º 3
0
 def __add_file(self, **args):
     logdebug(LOGGER, 'Adding file "%s" with handle "%s".', args['file_name'], args['file_handle'])
     self.__add_file_to_datasets_children(args['file_handle'])
     self.__adapt_file_args(args)
     self.__create_and_store_file_publication_message(args)        
     self.__set_machine_state_to_files_added()
     logtrace(LOGGER, 'Adding file done.')
Exemplo n.º 4
0
 def first_connection(self):
     logdebug(LOGGER, 'Trigger connection to rabbit...')
     self.__trigger_connection_to_rabbit_etc()
     logdebug(LOGGER, 'Trigger connection to rabbit... done.')
     logdebug(LOGGER, 'Start waiting for events...')
     self.__start_waiting_for_events()
     logtrace(LOGGER, 'Had started waiting for events, but stopped.')
Exemplo n.º 5
0
 def __get_message_from_stack(self, seconds=0):
     message = self.thread.get_message_from_unpublished_stack(seconds)
     logtrace(
         LOGGER,
         'Found message to be published. Now left in queue to be published: %i messages.',
         self.thread.get_num_unpublished())
     return message
Exemplo n.º 6
0
    def __publish_message_to_channel(self):

        # Find a message to publish.
        # If no messages left, well, nothing to publish!
        try:
            message = self.__get_message_from_stack()
        except queue.Empty as e:
            logtrace(LOGGER, 'Queue empty. No more messages to be published.')
            return

        # Now try to publish it.
        # If anything goes wrong, you need to put it back to
        # the stack of unpublished messages!
        try:
            success = self.__try_publishing_otherwise_put_back_to_stack(message)
            if success:
                self.__postparations_after_successful_feeding(message)

        # Treat various errors that may occur during publishing:
        except pika.exceptions.ChannelClosed as e:
            logwarn(LOGGER, 'Cannot publish message %i to RabbitMQ because the Channel is closed (%s)', self.__delivery_number+1, repr(e))

        except AttributeError as e:
            if self.thread._channel is None:
                logwarn(LOGGER, 'Cannot publish message %i to RabbitMQ because there is no channel.', self.__delivery_number+1)
            else:
                logwarn(LOGGER, 'Cannot publish message %i to RabbitMQ (unexpected error %s:%s)', self.__delivery_number+1, e.__class__.__name__, repr(e))

        except AssertionError as e:
            logwarn(LOGGER, 'Cannot publish message to RabbitMQ %i because of AssertionError: "%s"', self.__delivery_number+1,e)
            if 'A non-string value was supplied for self.exchange' in repr(e):
                exch = self.thread.get_exchange_name()
                logwarn(LOGGER, 'Exchange was "%s" (type %s)', exch, type(exch))
Exemplo n.º 7
0
def get_routing_key_and_string_message_from_message_if_possible(msg):

    # Try to convert message to json:
    json_ok = False
    msg_json = None
    msg_string = None

    if msg is None:
        raise ValueError('The message that was passed is None.')

    # Get JSON from message, if possible!
    if isinstance(msg, basestring):

        try:
            # Valid string message --> JSON
            msg_string = msg
            msg_json = json.loads(msg)
            json_ok = True
            logdebug(LOGGER, 'Message was transformed to json.')
        except ValueError as e:

            # Invalid string message
            loginfo(LOGGER, 'Message seems to be invalid json: %s', msg)
            msg_string = str(msg)
            json_ok = False
    else:
        try:
            # Message is json already.
            msg_string = json.dumps(msg)
            msg_json = msg
            json_ok = True
            logtrace(LOGGER, 'Message was already json.')

        except TypeError as e:
            if 'not JSON serializable' in e.message:

                # Message was whatever.
                msg_string = str(msg)
                json_ok = False
                msg = (
                    'Message was neither JSON nor string and not understandable: %s'
                    % msg_string)
                loginfo(LOGGER, msg)
                raise ValueError(msg)

    # If we succeeded, try to get routing key:
    routing_key = None
    if json_ok:
        try:
            routing_key = msg_json['ROUTING_KEY']
            logtrace(LOGGER, 'Routing key extracted from message.')
        except (KeyError, TypeError) as e:
            logdebug(LOGGER, 'No routing key in message.')
            routing_key = esgfpid.defaults.RABBIT_DEFAULT_ROUTING_KEY
            pass  # There is no routing key in the message
    else:
        routing_key = esgfpid.defaults.RABBIT_DEFAULT_ROUTING_KEY

    return routing_key, msg_string
Exemplo n.º 8
0
    def __iterate_over_all_hosts(self):
        success = False
        print_conn = True
        print_chan = True
        self.channel_ok = False

        while True:
            try:
                if print_conn:
                    self.__loginfo(
                        ' .. checking authentication and connection ...')
                    print_conn = False
                    print_chan = True

                self.connection = self.__check_making_rabbit_connection()

                if print_chan:
                    self.__loginfo(
                        ' .. checking authentication and connection ... ok.')
                    self.__loginfo(' .. checking channel ...')
                    print_chan = False
                    print_conn = True

                self.channel_ok = False
                self.channel = self.__check_opening_channel(self.connection)
                self.channel_ok = True
                self.__check_exchange_existence(self.channel)

                if self.__send_message:
                    if self.__prefix is None:
                        # Cannot happen, as we get it from the connector object.
                        raise esgfpid.exceptions.ArgumentError(
                            'Missing handle prefix!')

                    self.__check_send_print_message(self.channel)

                success = True

                break  # success, leave loop

            except ValueError as e:

                self.__loginfo(' .. giving this node a lower priority..')
                self.__nodemanager.set_priority_low_for_current()

                if self.__nodemanager.has_more_urls(
                ):  # stay in loop, try next host
                    utils.logtrace(LOGGER, 'Left URLs: %s',
                                   self.__nodemanager.get_num_left_urls())
                    self.__nodemanager.set_next_host()
                    self.__current_rabbit_host = self.__nodemanager.get_connection_parameters(
                    ).host
                    utils.logtrace(LOGGER, 'Now trying: %s',
                                   self.__current_rabbit_host)

                else:  # definitive fail, leave loop
                    break

        return success
Exemplo n.º 9
0
 def __remove_delivery_tag_and_message_single(self, deliv_tag):
     try:
         self.__unconfirmed_delivery_tags.remove(deliv_tag)
         ms = self.__unconfirmed_messages_dict.pop(str(deliv_tag))
         logtrace(LOGGER, 'Received ack for message %s.', ms)
     except ValueError as e:
         logdebug(LOGGER, 'Could not remove %i from unconfirmed.',
                  deliv_tag)
Exemplo n.º 10
0
 def __react_on_single_delivery_ack(self, deliv_tag):
     self.__remove_delivery_tag_and_message_single(deliv_tag)
     logdebug(LOGGER,
              'Received ack for delivery tag %i. Waiting for %i confirms.',
              deliv_tag, len(self.__unconfirmed_delivery_tags))
     logtrace(LOGGER, 'Received ack for delivery tag %i.', deliv_tag)
     logtrace(LOGGER, 'Now left in queue to be confirmed: %i messages.',
              len(self.__unconfirmed_delivery_tags))
Exemplo n.º 11
0
    def __make_ready_for_publishing(self):
        logdebug(
            LOGGER,
            '(Re)connection established, making ready for publication...')

        # Check for unexpected errors:
        if self.thread._channel is None:
            logerror(
                LOGGER,
                'Channel is None after connecting to server. This should not happen.'
            )
            self.statemachine.set_to_permanently_unavailable()
        if self.thread._connection is None:
            logerror(
                LOGGER,
                'Connection is None after connecting to server. This should not happen.'
            )
            self.statemachine.set_to_permanently_unavailable()

        # Normally, it should already be waiting to be available:
        if self.statemachine.is_WAITING_TO_BE_AVAILABLE():
            logdebug(LOGGER, 'Setup is finished. Publishing may start.')
            logtrace(LOGGER, 'Publishing will use channel no. %s!',
                     self.thread._channel.channel_number)
            self.statemachine.set_to_available()
            self.__check_for_already_arrived_messages_and_publish_them()

        # It was asked to close in the meantime (but might be able to publish the last messages):
        elif self.statemachine.is_AVAILABLE_BUT_WANTS_TO_STOP():
            logdebug(
                LOGGER,
                'Setup is finished, but the module was already asked to be closed in the meantime.'
            )
            self.__check_for_already_arrived_messages_and_publish_them()

        # It was force-closed in the meantime:
        elif self.statemachine.is_PERMANENTLY_UNAVAILABLE(
        ):  # state was set in shutter module's __close_down()
            if self.statemachine.get_detail_closed_by_publisher():
                logdebug(
                    LOGGER,
                    'Setup is finished now, but the module was already force-closed in the meantime.'
                )
                self.shutter.safety_finish(
                    'closed before connection was ready. reclosing.')
            elif self.statemachine.detail_could_not_connect:
                logerror(
                    LOGGER,
                    'This is not supposed to happen. If the connection failed, this part of the code should not be reached.'
                )
            else:
                logerror(
                    LOGGER,
                    'This is not supposed to happen. An unknown event set this module to be unavailable. When was this set to unavailable?'
                )
        else:
            logdebug(LOGGER, 'Unexpected state.')
Exemplo n.º 12
0
 def __log_publication_trigger(self):
     if self.__first_publication_trigger:
         logdebug(
             LOGGER,
             'Received first trigger for publishing message to RabbitMQ.')
         self.__first_publication_trigger = False
     logtrace(
         LOGGER,
         'Received trigger for publishing message to RabbitMQ, and module is ready to accept it.'
     )
Exemplo n.º 13
0
 def on_channel_open(self, channel):
     time_passed = datetime.datetime.now() - self.__start_connect_time
     logdebug(
         LOGGER, 'Opening channel... done. Took %s seconds.' %
         time_passed.total_seconds())
     logtrace(LOGGER, 'Channel has number: %s.', channel.channel_number)
     self.thread._channel = channel
     self.__reconnect_counter = 0
     self.__add_on_channel_close_callback()
     self.__add_on_return_callback()
     self.__make_channel_confirm_delivery()
     self.__make_ready_for_publishing()
Exemplo n.º 14
0
 def __wait_and_trigger_reconnection(self, connection, wait_seconds):
     if self.statemachine.is_FORCE_FINISHED():
         errormsg = 'Permanently failed to connect to RabbitMQ. Tried all hosts until received a force-finish. Giving up. No PID requests will be sent.'
         self.__give_up_reconnecting_and_raise_exception(errormsg)
     else:
         self.statemachine.set_to_waiting_to_be_available()
         loginfo(LOGGER, 'Trying to reconnect to RabbitMQ in %s seconds.',
                 wait_seconds)
         connection.add_timeout(wait_seconds, self.reconnect)
         logtrace(LOGGER,
                  'Reconnect event added to connection %s (not to %s)',
                  connection, self.thread._connection)
Exemplo n.º 15
0
    def set_priority_low_for_current(self):
        # We do not change the priority stored ass attribute in the
        # dicts, BUT we change the priority under which it is stored in
        # the list of nodes to be used.

        # Deal with open or trusted node:
        if self.__current_node['is_open']:
            where_to_look = self.__open_nodes_archive
        else:
            where_to_look = self.__trusted_nodes_archive

        # Go over all nodes of the current prio to find the
        # current one, then move it to a different prio:
        moved = False
        try:
            current_prio = self.__current_node['priority']
            moved = self.__move_to_last_prio(current_prio, where_to_look)
            if moved: return  # changed successfully!

        except KeyError as e:
            logsafe = make_logsafe(where_to_look)
            errmsg = 'No node of prio %s found. Nodes: %s.' % (current_prio,
                                                               logsafe)
            logwarn(LOGGER, errmsg)

            # The node had already been added to the last-prio nodes ?!
            last_already = self.__is_this_node_in_last_prio_already(
                where_to_look)
            if last_already:
                logdebug(LOGGER, 'Node already had lowest priority.')
                return  # nothing to change!

        # This is extremely unlikely - in fact I don't see how it could occur:
        if (not moved) and (not last_already):
            errmsg = 'Could not find this node\'s priority (%s), nor the last-priority (%s). Somehow this node\'s priority was changed weirdly.' % (
                current_prio, LAST_PRIO)
            logwarn(LOGGER, errmsg)
            logsafe = make_logsafe(where_to_look)
            logwarn(LOGGER, 'All nodes: %s' % logsafe)

            # No matter where the node is stored, move it to "last" prio:
            for prio, nodes in where_to_look.items():

                logtrace(LOGGER, 'Looking in prio "%s"...' % prio)
                moved = self.__move_to_last_prio(prio, where_to_look)
                if moved: return  # changed successfully!

            errmsg = 'Node definitely not found, cannot change prio.'
            logwarn(LOGGER, errmsg)
            raise ValueError(errmsg)
Exemplo n.º 16
0
    def __iterate_over_all_hosts(self):
        success = False
        print_conn = True
        print_chan = True
        self.channel_ok = False

        while True:
            try:
                if print_conn:
                    self.__loginfo(
                        ' .. checking authentication and connection ...')
                    print_conn = False
                    print_chan = True

                self.connection = self.__check_making_rabbit_connection()

                if print_chan:
                    self.__loginfo(
                        ' .. checking authentication and connection ... ok.')
                    self.__loginfo(' .. checking channel ...')
                    print_chan = False
                    print_conn = True

                self.channel_ok = False
                self.channel = self.__check_opening_channel(self.connection)
                self.channel_ok = True
                self.__check_exchange_existence(self.channel)

                success = True

                break  # success, leave loop

            except ValueError as e:

                if self.__nodemanager.has_more_urls(
                ):  # stay in loop, try next host
                    utils.logtrace(LOGGER, 'Left URLs: %s',
                                   self.__nodemanager.get_num_left_urls())
                    self.__nodemanager.set_next_host()
                    self.__current_rabbit_host = self.__nodemanager.get_connection_parameters(
                    ).host
                    utils.logtrace(LOGGER, 'Now trying: %s',
                                   self.__current_rabbit_host)

                else:  # definitive fail, leave loop
                    break

        return success
Exemplo n.º 17
0
    def __react_on_ack(self, deliv_tag, multiple):
        if self.__first_confirm_receival:
            self.__first_confirm_receival = False
            loginfo(LOGGER,
                    'Received first message confirmation from RabbitMQ.')

        if multiple:
            logtrace(
                LOGGER,
                'Received "ACK" for multiple messages from messaging service.')
            self.__react_on_multiple_delivery_ack(deliv_tag)
        else:
            logtrace(
                LOGGER,
                'Received "ACK" for single message from messaging service.')
            self.__react_on_single_delivery_ack(deliv_tag)
Exemplo n.º 18
0
    def __postparations_after_successful_feeding(self, msg):

        # Pass the successfully published message and its delivery_number
        # to the confirmer module, to wait for its confirmation.
        # Increase the delivery number for the next message.
        self.thread.put_to_unconfirmed_delivery_tags(self.__delivery_number)
        self.thread.put_to_unconfirmed_messages_dict(self.__delivery_number, msg)
        self.__delivery_number += 1

        # Logging
        self.__logcounter_success += 1
        log_every_x_times(LOGGER, self.__logcounter_success, self.__LOGFREQUENCY, 'Actual publish to channel done (trigger no. %i, publish no. %i).', self.__logcounter_trigger, self.__logcounter_success)
        logtrace(LOGGER, 'Publishing messages %i to RabbitMQ... done.', self.__delivery_number-1)
        if (self.__delivery_number-1 == 1):
            loginfo(LOGGER, 'First message published to RabbitMQ.')
        logdebug(LOGGER, 'Message published (no. %i)', self.__delivery_number-1)
Exemplo n.º 19
0
    def on_delivery_confirmation(self, method_frame):
        deliv_tag, confirmation_type, multiple = self.__get_confirm_info(
            method_frame)
        log_every_x_times(LOGGER, self.__logcounter, self.__LOGFREQUENCY,
                          'Received a confirm (%s)', confirmation_type)
        self.__logcounter += 1

        if confirmation_type == 'ack':
            logtrace(LOGGER, 'Received "ACK" from messaging service.')
            self.__react_on_ack(deliv_tag, multiple)
        elif confirmation_type == 'nack':
            logtrace(LOGGER, 'Received "NACK" from messaging service.')
            self.__react_on_nack(deliv_tag, multiple)
        else:
            msg = 'Received asynchronous response of unknown type from messaging service.'
            logwarn(LOGGER, msg)
            raise UnknownServerResponse(msg + ':' + str(method_frame))
Exemplo n.º 20
0
 def make_permanently_closed_by_user(self):
     # This changes the state of the state machine!
     # This needs to be called from the shutter module
     # in case there is a force_finish while the connection
     # is already closed (as the callback on_connection_closed
     # is not called then).
     self.statemachine.set_to_permanently_unavailable()
     logtrace(LOGGER, 'Stop waiting for events due to user interrupt!')
     logtrace(LOGGER,
              'Permanent close: Stopping ioloop of connection %s...',
              self.thread._connection)
     self.thread._connection.ioloop.stop()
     loginfo(LOGGER, 'Stopped listening for RabbitMQ events (%s).',
             get_now_utc_as_formatted_string())
     logdebug(
         LOGGER,
         'Connection to messaging service closed by user. Will not reopen.')
Exemplo n.º 21
0
 def __log_why_cannot_feed_the_rabbit_now(self):
     log_every_x_times(
         LOGGER, self.__logcounter_trigger, self.__LOGFREQUENCY,
         'Cannot publish message to RabbitMQ (trigger no. %i).',
         self.__logcounter_trigger)
     if self.statemachine.is_WAITING_TO_BE_AVAILABLE():
         logdebug(
             LOGGER,
             'Cannot publish message to RabbitMQ yet, as the connection is not ready.'
         )
     elif self.statemachine.is_NOT_STARTED_YET():
         logerror(
             LOGGER,
             'Cannot publish message to RabbitMQ, as the thread is not running yet.'
         )
     elif self.statemachine.is_PERMANENTLY_UNAVAILABLE(
     ) or self.statemachine.is_FORCE_FINISHED():
         if self.statemachine.detail_could_not_connect:
             logtrace(
                 LOGGER,
                 'Could not publish message to RabbitMQ, as the connection failed.'
             )
             if self.__have_not_warned_about_connection_fail_yet:
                 logwarn(
                     LOGGER,
                     'Could not publish message(s) to RabbitMQ. The connection failed definitively.'
                 )
                 self.__have_not_warned_about_connection_fail_yet = False
         elif self.statemachine.get_detail_closed_by_publisher():
             logtrace(
                 LOGGER,
                 'Cannot publish message to RabbitMQ, as the connection was closed by the user.'
             )
             if self.__have_not_warned_about_force_close_yet:
                 logwarn(
                     LOGGER,
                     'Could not publish message(s) to RabbitMQ. The sender was closed by the user.'
                 )
                 self.__have_not_warned_about_force_close_yet = False
     else:
         if self.thread._channel is None:
             logerror(
                 LOGGER,
                 'Very unexpected. Could not publish message(s) to RabbitMQ. There is no channel.'
             )
Exemplo n.º 22
0
    def __is_this_node_in_last_prio_already(self, where_to_look):
        try:
            list_candidates = where_to_look[LAST_PRIO]
        except KeyError as e:
            errmsg = 'No node of last prio (%s) exists.' % LAST_PRIO
            logwarn(LOGGER, errmsg)
            return False

        for i in range(len(list_candidates)):
            candidate = list_candidates[i]
            if self.__compare_nodes(candidate, self.__current_node):
                logtrace(
                    LOGGER,
                    'Found current node in archive (in list of last-prio nodes).'
                )
                return True

        return False
Exemplo n.º 23
0
 def __wait_and_trigger_reconnection(self, connection, wait_seconds):
     if self.statemachine.is_FORCE_FINISHED():
         # TODO This is the same code as above. Make a give_up function from it?
         #self.statemachine.set_to_permanently_unavailable()
         #self.statemachine.detail_could_not_connect = True
         #max_tries = defaults.RABBIT_RECONNECTION_MAX_TRIES
         errormsg = (
             'Permanently failed to connect to RabbitMQ. Tried all hosts %s until received a force-finish. Giving up. No PID requests will be sent.'
             % list(self.__all_hosts_that_were_tried))
         logerror(LOGGER, errormsg)
         raise PIDServerException(errormsg)
     else:
         self.statemachine.set_to_waiting_to_be_available()
         loginfo(LOGGER, 'Trying to reconnect to RabbitMQ in %s seconds.',
                 wait_seconds)
         connection.add_timeout(wait_seconds, self.reconnect)
         logtrace(LOGGER,
                  'Reconnect event added to connection %s (not to %s)',
                  connection, self.thread._connection)
Exemplo n.º 24
0
    def on_message_not_accepted(self, channel, returned_frame, props, body):
        # Messages that are returned are confirmed anyways.
        # If we sent 20 messages that are returned, all 20 are acked,
        # so we do not need to retrieve them from the unconfirmed
        # messages after resending.
        # In the end, we'll have published 40 messages and received 40 acks.

        # Logging...
        logtrace(
            LOGGER, 'Return frame: %s', returned_frame
        )  # <Basic.Return(['exchange=rabbitsender_integration_tests', 'reply_code=312', 'reply_text=NO_ROUTE', 'routing_key=cmip6.publisher.HASH.cart.datasets'])>
        logtrace(
            LOGGER, 'Return props: %s', props
        )  # <BasicProperties(['content_type=application/json', 'delivery_mode=2'])>
        logtrace(LOGGER, 'Return body: %s', body)

        # Was it the first or second time it comes back?
        if returned_frame.reply_text == 'NO_ROUTE':
            loginfo(
                LOGGER,
                'The message was returned because it could not be assigned to any queue. No binding for routing key "%s".',
                returned_frame.routing_key)
            if returned_frame.routing_key.startswith(
                    esgfpid.utils.RABBIT_EMERGENCY_ROUTING_KEY):
                self.__log_about_double_return(returned_frame, body)
            else:
                self.__resend_message(returned_frame, props, body)
        else:
            logerror(
                LOGGER,
                'The message was returned. Routing key: %s. Unknown reason: %s',
                returned_frame.routing_key, returned_frame.reply_text)
            self.__resend_message(returned_frame, props, body)
Exemplo n.º 25
0
    def __try_publishing_otherwise_put_back_to_stack(self, message):
        try:
            # Getting message info:
            properties = self.nodemanager.get_properties_for_message_publications()
            routing_key, msg_string = rabbitutils.get_routing_key_and_string_message_from_message_if_possible(message)
            routing_key = self.nodemanager.adapt_routing_key_for_untrusted(routing_key)
            
            # Logging
            logtrace(LOGGER, 'Publishing message %i (key %s) (body %s)...', self.__delivery_number+1, routing_key, msg_string) # +1 because it will be incremented after the publish.
            log_every_x_times(LOGGER, self.__logcounter_trigger, self.__LOGFREQUENCY, 'Trying actual publish... (trigger no. %i).', self.__logcounter_trigger)
            logtrace(LOGGER, '(Publish to channel no. %i).', self.thread._channel.channel_number)

            # Actual publish to exchange
            self.thread._channel.basic_publish(
                exchange=self.thread.get_exchange_name(),
                routing_key=routing_key,
                body=msg_string,
                properties=properties,
                mandatory=defaults.RABBIT_MANDATORY_DELIVERY
            )
            return True

        # If anything went wrong, put it back into the stack of
        # unpublished messages before re-raising the exception
        # for further handling:
        except Exception as e:
            success = False
            logwarn(LOGGER, 'Message was not published. Putting back to queue. Reason: %s: "%s"',e.__class__.__name__, repr(e))
            self.thread.put_one_message_into_queue_of_unsent_messages(message)
            logtrace(LOGGER, 'Now (after putting back) left in queue to be published: %i messages.', self.thread.get_num_unpublished())
            raise e
Exemplo n.º 26
0
    def __move_to_last_prio(self, current_prio, all_nodes):

        list_candidates = all_nodes[current_prio]
        logsafe = make_logsafe(list_candidates)
        loginfo(LOGGER, 'Nodes of prio "%s": %s', current_prio, logsafe)

        for i in range(len(list_candidates)):
            candidate = list_candidates[i]
            if self.__compare_nodes(candidate, self.__current_node):
                logtrace(LOGGER, 'Found current node in archive.')

                # Add to lowest prio:
                try:
                    all_nodes[LAST_PRIO].append(candidate)
                    logdebug(
                        LOGGER,
                        'Added this host to list of lowest prio hosts...')

                except KeyError:
                    all_nodes[LAST_PRIO] = [candidate]
                    logdebug(
                        LOGGER,
                        'Added this host to (newly-created) list of lowest prio hosts...'
                    )

                # Remove from current prio:
                list_candidates.pop(i)
                loginfo(LOGGER,
                        'Removed this host from list of hosts with prio %s!',
                        current_prio)
                if len(list_candidates) == 0:
                    all_nodes.pop(current_prio)
                    loginfo(LOGGER, 'Removed the current priority %s!',
                            current_prio)
                return True

        return False
Exemplo n.º 27
0
    def make_permanently_closed_by_error(self, connection, reply_text):
        # This changes the state of the state machine!
        # This needs to be called if there is a permanent
        # error and we don't want the library to reonnect,
        # and we also don't want to pretend it was closed
        # by the user.
        # This is really rarely needed.
        self.statemachine.set_to_permanently_unavailable()
        logtrace(LOGGER, 'Stop waiting for events due to permanent error!')

        # In case the main thread was waiting for any synchronization event.
        self.thread.unblock_events()

        # Close ioloop, which blocks the thread.
        logdebug(LOGGER,
                 'Permanent close: Stopping ioloop of connection %s...',
                 self.thread._connection)
        self.thread._connection.ioloop.stop()
        loginfo(LOGGER, 'Stopped listening for RabbitMQ events (%s).',
                get_now_utc_as_formatted_string())
        logdebug(
            LOGGER,
            'Connection to messaging service closed because of error. Will not reopen. Reason: %s',
            reply_text)
Exemplo n.º 28
0
 def __create_and_send_dataset_publication_message_to_queue(self):
     self.__remove_duplicates_from_list_of_file_handles()
     message = self.__create_dataset_publication_message()
     self.__send_message_to_queue(message)
     logdebug(LOGGER, 'Dataset publication message handed to rabbit thread.')
     logtrace(LOGGER, 'Dataset publication message: %s (%s, version %s).', self.__dataset_handle, self.__drs_id, self.__version_number)
Exemplo n.º 29
0
 def __make_channel_confirm_delivery(self):
     logtrace(LOGGER,
              'Set confirm delivery... (Issue Confirm.Select RPC command)')
     self.thread._channel.confirm_delivery(
         callback=self.confirmer.on_delivery_confirmation)
     logdebug(LOGGER, 'Set confirm delivery... done.')
Exemplo n.º 30
0
    def __start_waiting_for_events(self):
        '''
        This waits until the whole chain of callback methods triggered by
        "trigger_connection_to_rabbit_etc()" has finished, and then starts 
        waiting for publications.
        This is done by starting the ioloop.

        Note: In the pika usage example, these things are both called inside the run()
        method, so I wonder if this check-and-wait here is necessary. Maybe not.
        But the usage example does not implement a Thread, so it probably blocks during
        the opening of the connection. Here, as it is a different thread, the run()
        might get called before the __init__ has finished? I'd rather stay on the
        safe side, as my experience of threading in Python is limited.
        '''

        # Start ioloop if connection object ready:
        if self.thread._connection is not None:
            try:
                logdebug(LOGGER, 'Starting ioloop...')
                logtrace(LOGGER, 'ioloop is owned by connection %s...',
                         self.thread._connection)

                # Tell the main thread that we're now open for events.
                # As soon as the thread._connection object is not None anymore, it
                # can receive events.
                self.thread.tell_publisher_to_stop_waiting_for_thread_to_accept_events(
                )
                self.thread.continue_gently_closing_if_applicable()
                self.thread._connection.ioloop.start()

            except pika.exceptions.ProbableAuthenticationError as e:

                time_passed = datetime.datetime.now(
                ) - self.__start_connect_time
                logerror(
                    LOGGER,
                    'Caught Authentication Exception after %s seconds during connection ("%s").',
                    time_passed.total_seconds(), e.__class__.__name__)
                self.statemachine.set_to_waiting_to_be_available()
                self.statemachine.detail_authentication_exception = True  # TODO WHAT FOR?

                # It seems that ProbableAuthenticationErrors do not cause
                # RabbitMQ to call any callback, either on_connection_closed
                # or on_connection_error - it just silently swallows the
                # problem.
                # So we need to manually trigger reconnection to the next
                # host here, which we do by manually calling the callback.
                errorname = 'ProbableAuthenticationError issued by pika'
                self.on_connection_error(self.thread._connection, errorname)

                # We start the ioloop, so it can handle the reconnection events,
                # or also receive events from the publisher in the meantime.
                self.thread._connection.ioloop.start()

            except Exception as e:
                # This catches any error during connection startup and during the entire
                # time the ioloop runs, blocks and waits for events.
                logerror(
                    LOGGER,
                    'Unexpected error during event listener\'s lifetime: %s: %s',
                    e.__class__.__name__, e.message)

                # As we will try to reconnect, set state to waiting to connect.
                # If reconnection fails, it will be set to permanently unavailable.
                self.statemachine.set_to_waiting_to_be_available()

                # In case this error is reached, it seems that no callback
                # was called that handles the problem. Let's try to reconnect
                # somewhere else.
                errorname = 'Unexpected error (' + str(
                    e.__class__.__name__) + ': ' + str(e.message) + ')'
                self.on_connection_error(self.thread._connection, errorname)

                # We start the ioloop, so it can handle the reconnection events,
                # or also receive events from the publisher in the meantime.
                self.thread._connection.ioloop.start()

        else:
            # I'm quite sure that this cannot happen, as the connection object
            # is created in "trigger_connection_...()" and thus exists, no matter
            # if the actual connection to RabbitMQ succeeded (yet) or not.
            logdebug(LOGGER,
                     'This cannot happen: Connection object is not ready.')
            logerror(
                LOGGER,
                'Cannot happen. Cannot properly start the thread. Connection object is not ready.'
            )