Example #1
0
 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
Example #2
0
 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
Example #3
0
 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