From aa8516dd53a642f354e5da3830872996d5f26d4a Mon Sep 17 00:00:00 2001 From: Julien Muchembled <jm@nexedi.com> Date: Fri, 19 Feb 2010 17:56:03 +0000 Subject: [PATCH] CMFActivity: use a new 'retry' column to count the number of failures Now, all messages can be executed 6 times by default (or more in case of ConflictError), regardless their initial priority. For compatibility reasons, the 'priority' column is still increased. git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@32877 20353a03-c40f-0410-a6d1-a30d3c3de9de --- product/CMFActivity/Activity/SQLBase.py | 34 ++++++++++--------- .../CMFActivity/dtml/manageActivities.dtml | 4 +-- .../skins/activity/SQLBase_reactivate.zsql | 13 ++++--- .../activity/SQLQueue_createMessageTable.zsql | 1 + product/CMFActivity/tests/testCMFActivity.py | 7 ++-- product/ERP5Type/tests/ERP5TypeTestCase.py | 2 +- 6 files changed, 33 insertions(+), 28 deletions(-) diff --git a/product/CMFActivity/Activity/SQLBase.py b/product/CMFActivity/Activity/SQLBase.py index d605a755fa..cac604acbe 100644 --- a/product/CMFActivity/Activity/SQLBase.py +++ b/product/CMFActivity/Activity/SQLBase.py @@ -35,7 +35,7 @@ from Products.CMFActivity.ActiveObject import ( INVOKE_ERROR_STATE, VALIDATE_ERROR_STATE) from Queue import VALIDATION_ERROR_DELAY -MAX_PRIORITY = 5 +MAX_RETRY = 5 class SQLBase: @@ -67,7 +67,7 @@ class SQLBase: activity=class_name, uid=line.uid, processing_node=line.processing_node, - priority=line.priority, + retry=line.retry, processing=line.processing) for line in readMessageList(path=None, method_id=None, @@ -133,10 +133,10 @@ class SQLBase: If anything failed, make successful messages available (if any), and the following rules apply to failed messages: - Failures due to ConflictErrors cause messages to be postponed, - but their priority is *not* increased. - - Failures of messages already above maximum priority cause them to + but their retry count is *not* increased. + - Failures of messages already above maximum retry count cause them to be put in a permanent-error state. - - In all other cases, priority is increased and message is delayed. + - In all other cases, retry count is increased and message is delayed. """ deletable_uid_list = [] delay_uid_list = [] @@ -161,7 +161,6 @@ class SQLBase: # should they be just made available again ? if uid_to_duplicate_uid_list_dict is not None: make_available_uid_list += uid_to_duplicate_uid_list_dict.get(uid, ()) - priority = m.line.priority # BACK: Only exceptions can be classes in Python 2.6. # Once we drop support for Python 2.4, # please, remove the "type(m.exc_type) is type(ConflictError)" check @@ -169,19 +168,23 @@ class SQLBase: if type(m.exc_type) is type(ConflictError) and \ issubclass(m.exc_type, ConflictError): delay_uid_list.append(uid) - elif priority > MAX_PRIORITY: - notify_user_list.append(m) - final_error_uid_list.append(uid) else: + retry = m.line.retry + if retry >= MAX_RETRY: + notify_user_list.append(m) + final_error_uid_list.append(uid) + continue + # XXX: What about making delay quadratic to the number of retries ? + delay = VALIDATION_ERROR_DELAY #* (retry * retry + 1) / 2 try: # Immediately update, because values different for every message activity_tool.SQLBase_reactivate(table=self.sql_table, uid=[uid], - delay=None, - priority=priority + 1) + delay=delay, + retry=1) except: - self._log(WARNING, 'Failed to increase priority of %r' % uid) - delay_uid_list.append(uid) + self._log(WARNING, 'Failed to reactivate %r' % uid) + make_available_uid_list.append(uid) else: # Internal CMFActivity error: the message can not be executed because # something is missing (context object cannot be found, method cannot @@ -198,12 +201,11 @@ class SQLBase: self._log(TRACE, 'Deleted messages %r' % deletable_uid_list) if delay_uid_list: try: - # If this is a conflict error, do not lower the priority but only delay. + # If this is a conflict error, do not increase 'retry' but only delay. activity_tool.SQLBase_reactivate(table=self.sql_table, - uid=delay_uid_list, delay=VALIDATION_ERROR_DELAY, priority=None) + uid=delay_uid_list, delay=VALIDATION_ERROR_DELAY, retry=None) except: self._log(ERROR, 'Failed to delay %r' % delay_uid_list) - make_available_uid_list += delay_uid_list if final_error_uid_list: try: activity_tool.SQLBase_assignMessage(table=self.sql_table, diff --git a/product/CMFActivity/dtml/manageActivities.dtml b/product/CMFActivity/dtml/manageActivities.dtml index 48bc4f703b..28b3ddf5eb 100644 --- a/product/CMFActivity/dtml/manageActivities.dtml +++ b/product/CMFActivity/dtml/manageActivities.dtml @@ -49,7 +49,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. <th align="left" valign="top">Arguments</th> <th align="left" valign="top">Named Parameters</th> <th align="left" valign="top">Processing Node</th> - <th align="left" valign="top">Priority</th> + <th align="left" valign="top">Retry</th> <th align="left" valign="top">Processing</th> <th align="left" valign="top">Call Traceback</th> </tr> @@ -83,7 +83,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. </dtml-if> </td> <td align="left" valign="top"><dtml-var processing_node></td> - <td align="left" valign="top"><dtml-var priority></td> + <td align="left" valign="top"><dtml-var retry></td> <td align="left" valign="top"> <dtml-if expr="processing is not None"> <dtml-var processing> diff --git a/product/CMFActivity/skins/activity/SQLBase_reactivate.zsql b/product/CMFActivity/skins/activity/SQLBase_reactivate.zsql index 1659b23647..1478428fda 100644 --- a/product/CMFActivity/skins/activity/SQLBase_reactivate.zsql +++ b/product/CMFActivity/skins/activity/SQLBase_reactivate.zsql @@ -9,18 +9,17 @@ class_file: </dtml-comment> <params>table uid:list -priority +retry delay </params> UPDATE <dtml-var table> SET - processing = 0 -<dtml-if expr="priority is not None"> - , priority = <dtml-sqlvar priority type="int"> -</dtml-if> -<dtml-if expr="delay is not None"> - , date = DATE_ADD(UTC_TIMESTAMP(), INTERVAL <dtml-sqlvar delay type="int"> SECOND) + date = DATE_ADD(UTC_TIMESTAMP(), INTERVAL + <dtml-sqlvar delay type="int"> SECOND) +<dtml-if expr="retry is not None"> + , priority = priority + <dtml-sqlvar retry type="int"> + , retry = retry + <dtml-sqlvar retry type="int"> </dtml-if> WHERE <dtml-sqltest uid type="int" multiple> diff --git a/product/CMFActivity/skins/activity/SQLQueue_createMessageTable.zsql b/product/CMFActivity/skins/activity/SQLQueue_createMessageTable.zsql index 80096ebcd6..5c7eda2188 100644 --- a/product/CMFActivity/skins/activity/SQLQueue_createMessageTable.zsql +++ b/product/CMFActivity/skins/activity/SQLQueue_createMessageTable.zsql @@ -20,6 +20,7 @@ CREATE TABLE `message_queue` ( `priority` TINYINT NOT NULL DEFAULT 0, `tag` VARCHAR(255) NOT NULL, `serialization_tag` VARCHAR(255) NOT NULL, + `retry` TINYINT UNSIGNED NOT NULL DEFAULT 0, `message` LONGBLOB NOT NULL, PRIMARY KEY (`uid`), KEY (`path`), diff --git a/product/CMFActivity/tests/testCMFActivity.py b/product/CMFActivity/tests/testCMFActivity.py index ab235d6790..a3eea7f7dc 100644 --- a/product/CMFActivity/tests/testCMFActivity.py +++ b/product/CMFActivity/tests/testCMFActivity.py @@ -1620,7 +1620,10 @@ class TestCMFActivity(ERP5TypeTestCase): def test_67_TestCancelFailedActiveObject(self, quiet=0, run=run_all_test): """Cancel an active object to make sure that it does not refer to - a persistent object.""" + a persistent object. + + XXX: this test fails if run first + """ if not run: return if not quiet: message = '\nTest if it is possible to safely cancel an active object' @@ -1657,7 +1660,7 @@ class TestCMFActivity(ERP5TypeTestCase): self.assertEquals(len(activity_tool.getMessageList()), 1) # Just wait for the active object to be abandoned. - self.flushAllActivities(silent=1, loop_size=10) + self.flushAllActivities(silent=1, loop_size=100) self.assertEquals(len(activity_tool.getMessageList()), 1) self.assertEquals(activity_tool.getMessageList()[0].processing_node, INVOKE_ERROR_STATE) diff --git a/product/ERP5Type/tests/ERP5TypeTestCase.py b/product/ERP5Type/tests/ERP5TypeTestCase.py index 13f9f0b17f..5ace57fc8f 100644 --- a/product/ERP5Type/tests/ERP5TypeTestCase.py +++ b/product/ERP5Type/tests/ERP5TypeTestCase.py @@ -698,7 +698,7 @@ class ERP5TypeTestCase(backportUnittest.TestCase, PortalTestCase): ) raise RuntimeError,\ 'tic is looping forever. These messages are pending: %r %s' % ( - [('/'.join(m.object_path), m.method_id, m.processing_node, m.priority) + [('/'.join(m.object_path), m.method_id, m.processing_node, m.retry) for m in portal_activities.getMessageList()], error_message ) -- 2.30.9