def dequeueMessage(self, activity_tool, processing_node): message_list, group_method_id, uid_to_duplicate_uid_list_dict = \ self.getProcessableMessageList(activity_tool, processing_node) if message_list: # Remove group_id parameter from group_method_id if group_method_id is not None: group_method_id = group_method_id.split('\0')[0] if group_method_id not in (None, ""): method = activity_tool.invokeGroup args = (group_method_id, message_list, self.__class__.__name__, hasattr(self, 'generateMessageUID')) activity_runtime_environment = ActivityRuntimeEnvironment(None) else: method = activity_tool.invoke message = message_list[0] args = (message, ) activity_runtime_environment = ActivityRuntimeEnvironment(message) # Commit right before executing messages. # As MySQL transaction does not start exactly at the same time as ZODB # transactions but a bit later, messages available might be called # on objects which are not available - or available in an old # version - to ZODB connector. # So all connectors must be committed now that we have selected # everything needed from MySQL to get a fresh view of ZODB objects. transaction.commit() transaction.begin() tv = getTransactionalVariable() tv['activity_runtime_environment'] = activity_runtime_environment # Try to invoke try: method(*args) # Abort if at least 1 message failed. On next tic, only those that # succeeded will be selected because their at_date won't have been # increased. for m in message_list: if m.getExecutionState() == MESSAGE_NOT_EXECUTED: raise _DequeueMessageException transaction.commit() except: exc_info = sys.exc_info() if exc_info[1] is not _DequeueMessageException: self._log(WARNING, 'Exception raised when invoking messages (uid, path, method_id) %r' % [(m.uid, m.object_path, m.method_id) for m in message_list]) for m in message_list: m.setExecutionState(MESSAGE_NOT_EXECUTED, exc_info, log=False) self._abort() exc_info = message_list[0].exc_info if exc_info: try: # Register it again. tv['activity_runtime_environment'] = activity_runtime_environment cancel = message.on_error_callback(*exc_info) del exc_info, message.exc_info transaction.commit() if cancel: message.setExecutionState(MESSAGE_EXECUTED) except: self._log(WARNING, 'Exception raised when processing error callbacks') message.setExecutionState(MESSAGE_NOT_EXECUTED) self._abort() self.finalizeMessageExecution(activity_tool, message_list, uid_to_duplicate_uid_list_dict) transaction.commit() return not message_list
def dequeueMessage(self, activity_tool, processing_node): message_list, group_method_id, uid_to_duplicate_uid_list_dict = \ self.getProcessableMessageList(activity_tool, processing_node) if message_list: # Remove group_id parameter from group_method_id if group_method_id is not None: group_method_id = group_method_id.split('\0')[0] if group_method_id not in (None, ""): method = activity_tool.invokeGroup args = (group_method_id, message_list, self.__class__.__name__, hasattr(self, 'generateMessageUID')) activity_runtime_environment = ActivityRuntimeEnvironment(None) else: method = activity_tool.invoke message = message_list[0] args = (message, ) activity_runtime_environment = ActivityRuntimeEnvironment(message) # Commit right before executing messages. # As MySQL transaction does not start exactly at the same time as ZODB # transactions but a bit later, messages available might be called # on objects which are not available - or available in an old # version - to ZODB connector. # So all connectors must be committed now that we have selected # everything needed from MySQL to get a fresh view of ZODB objects. transaction.commit() transaction.begin() tv = getTransactionalVariable() tv['activity_runtime_environment'] = activity_runtime_environment # Try to invoke try: method(*args) # Abort if at least 1 message failed. On next tic, only those that # succeeded will be selected because their at_date won't have been # increased. for m in message_list: if m.getExecutionState() == MESSAGE_NOT_EXECUTED: raise _DequeueMessageException transaction.commit() except: exc_info = sys.exc_info() if exc_info[1] is not _DequeueMessageException: self._log(WARNING, 'Exception raised when invoking messages (uid, path, method_id) %r' % [(m.uid, m.object_path, m.method_id) for m in message_list]) for m in message_list: m.setExecutionState(MESSAGE_NOT_EXECUTED, exc_info, log=False) self._abort() exc_info = message_list[0].exc_info if exc_info: try: # Register it again. tv['activity_runtime_environment'] = activity_runtime_environment cancel = message.on_error_callback(*exc_info) del exc_info, message.exc_info transaction.commit() if cancel: message.setExecutionState(MESSAGE_EXECUTED) except: self._log(WARNING, 'Exception raised when processing error callbacks') message.setExecutionState(MESSAGE_NOT_EXECUTED) self._abort() self.finalizeMessageExecution(activity_tool, message_list, uid_to_duplicate_uid_list_dict) transaction.commit() return not message_list
def dequeueMessage(self, activity_tool, processing_node): def makeMessageListAvailable(uid_list, uid_to_duplicate_uid_list_dict): final_uid_list = [] for uid in uid_list: final_uid_list.append(uid) final_uid_list.extend(uid_to_duplicate_uid_list_dict.get(uid, [])) self.makeMessageListAvailable(activity_tool=activity_tool, uid_list=final_uid_list) message_list, group_method_id, uid_to_duplicate_uid_list_dict = \ self.getProcessableMessageList(activity_tool, processing_node) if message_list: # Remove group_id parameter from group_method_id if group_method_id is not None: group_method_id = group_method_id.split('\0')[0] if group_method_id not in (None, ""): method = activity_tool.invokeGroup args = (group_method_id, message_list, self.__class__.__name__, self.merge_duplicate) activity_runtime_environment = ActivityRuntimeEnvironment(None) else: method = activity_tool.invoke message = message_list[0] args = (message, ) activity_runtime_environment = ActivityRuntimeEnvironment(message) # Commit right before executing messages. # As MySQL transaction does not start exactly at the same time as ZODB # transactions but a bit later, messages available might be called # on objects which are not available - or available in an old # version - to ZODB connector. # So all connectors must be committed now that we have selected # everything needed from MySQL to get a fresh view of ZODB objects. transaction.commit() transaction.begin() tv = getTransactionalVariable() tv['activity_runtime_environment'] = activity_runtime_environment # Try to invoke try: method(*args) except: self._log(WARNING, 'Exception raised when invoking messages (uid, path, method_id) %r' % [(m.uid, m.object_path, m.method_id) for m in message_list]) try: transaction.abort() except: # Unfortunately, database adapters may raise an exception against # abort. self._log(PANIC, 'abort failed, thus some objects may be modified accidentally') raise # XXX Is it still useful to free messages now that this node is able # to reselect them ? to_free_uid_list = [x.uid for x in message_list] try: makeMessageListAvailable(to_free_uid_list, uid_to_duplicate_uid_list_dict) except: self._log(ERROR, 'Failed to free messages: %r' % to_free_uid_list) else: self._log(TRACE, 'Freed messages %r' % to_free_uid_list) # Abort if something failed. if [m for m in message_list if m.getExecutionState() == MESSAGE_NOT_EXECUTED]: endTransaction = transaction.abort else: endTransaction = transaction.commit try: endTransaction() except: self._log(WARNING, 'Failed to end transaction for messages (uid, path, method_id) %r' % [(m.uid, m.object_path, m.method_id) for m in message_list]) if endTransaction == transaction.abort: self._log(PANIC, 'Failed to abort executed messages.' ' Some objects may be modified accidentally.') else: try: transaction.abort() except: self._log(PANIC, 'Failed to abort executed messages which also' ' failed to commit. Some objects may be modified accidentally.') raise exc_info = sys.exc_info() for m in message_list: m.setExecutionState(MESSAGE_NOT_EXECUTED, exc_info, log=False) try: makeMessageListAvailable([x.uid for x in message_list], uid_to_duplicate_uid_list_dict) except: self._log(ERROR, 'Failed to free remaining messages: %r' % (message_list, )) else: self._log(TRACE, 'Freed messages %r' % (message_list, )) self.finalizeMessageExecution(activity_tool, message_list, uid_to_duplicate_uid_list_dict) transaction.commit() return not message_list