Commit 6116b9dc authored by Kazuhiko Shiozaki's avatar Kazuhiko Shiozaki Committed by Vincent Pelletier

Timeout: introduce activity_timeout configuration.

Vincent Pelletier:
- Disable timeout by default.
parent 34c81caf
...@@ -41,6 +41,8 @@ from Products.CMFActivity.ActivityRuntimeEnvironment import ( ...@@ -41,6 +41,8 @@ from Products.CMFActivity.ActivityRuntimeEnvironment import (
DEFAULT_MAX_RETRY, ActivityRuntimeEnvironment) DEFAULT_MAX_RETRY, ActivityRuntimeEnvironment)
from Queue import Queue, VALIDATION_ERROR_DELAY from Queue import Queue, VALIDATION_ERROR_DELAY
from Products.CMFActivity.Errors import ActivityFlushError from Products.CMFActivity.Errors import ActivityFlushError
from Products.ERP5Type import Timeout
from Products.ERP5Type.Timeout import TimeoutReachedError, Deadline
# Stop validating more messages when this limit is reached # Stop validating more messages when this limit is reached
MAX_VALIDATED_LIMIT = 1000 MAX_VALIDATED_LIMIT = 1000
...@@ -646,7 +648,11 @@ CREATE TABLE %s ( ...@@ -646,7 +648,11 @@ CREATE TABLE %s (
transaction.begin() transaction.begin()
# Try to invoke # Try to invoke
try: try:
with activity_runtime_environment: # Refer Timeout.activity_timeout instead of
# from Products.ERP5Type.Timeout import activity_timeout
# so that we can override the value in Timeout namescope in unit tests.
offset = Timeout.activity_timeout
with activity_runtime_environment, Deadline(offset):
method(*args) method(*args)
# Abort if at least 1 message failed. On next tic, only those that # 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 # succeeded will be selected because their at_date won't have been
...@@ -737,7 +743,8 @@ CREATE TABLE %s ( ...@@ -737,7 +743,8 @@ CREATE TABLE %s (
else: else:
max_retry = m.max_retry max_retry = m.max_retry
retry = m.line.retry retry = m.line.retry
if max_retry is not None and retry >= max_retry: if (max_retry is not None and retry >= max_retry) or \
m.exc_type == TimeoutReachedError:
# Always notify when we stop retrying. # Always notify when we stop retrying.
notify_user_list.append((m, False)) notify_user_list.append((m, False))
final_error_uid_list.append(uid) final_error_uid_list.append(uid)
......
...@@ -2625,6 +2625,32 @@ class TestCMFActivity(ERP5TypeTestCase, LogInterceptor): ...@@ -2625,6 +2625,32 @@ class TestCMFActivity(ERP5TypeTestCase, LogInterceptor):
) )
self.tic() self.tic()
def test_activity_timeout(self):
slow_method_id = 'Base_getSlowObjectList'
createZODBPythonScript(
self.portal.portal_skins.custom,
slow_method_id,
'selection=None, **kw',
"""
from time import sleep
sleep(3)
return [x.getObject() for x in context.portal_catalog(limit=100)]
""")
# Set short enough activity timeout configuration
import Products.ERP5Type.Timeout
Products.ERP5Type.Timeout.activity_timeout = 2.0
self.portal.portal_templates.activate().Base_getSlowObjectList()
with self.assertRaises(RuntimeError):
self.tic()
message, = self.getMessageList('SQLDict')
self.assertEqual(message.retry, 0)
self.deleteMessageList(
'SQLDict',
[message],
)
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestCMFActivity)) suite.addTest(unittest.makeSuite(TestCMFActivity))
......
...@@ -48,6 +48,7 @@ del status_codes ...@@ -48,6 +48,7 @@ del status_codes
# Placeholder timeouts until product's "initialize" is called. # Placeholder timeouts until product's "initialize" is called.
publisher_timeout = None publisher_timeout = None
activity_timeout = None
_site_local = threading.local() _site_local = threading.local()
......
...@@ -162,6 +162,7 @@ def initialize( context ): ...@@ -162,6 +162,7 @@ def initialize( context ):
# Note: erp5_conf attributes are missing in unit tests, fallback to no timeout # Note: erp5_conf attributes are missing in unit tests, fallback to no timeout
# in that case. # in that case.
Timeout.publisher_timeout = getattr(erp5_conf, 'publisher_timeout', None) Timeout.publisher_timeout = getattr(erp5_conf, 'publisher_timeout', None)
Timeout.activity_timeout = getattr(erp5_conf, 'activity_timeout', None)
from AccessControl.SecurityInfo import allow_module from AccessControl.SecurityInfo import allow_module
from AccessControl.SecurityInfo import ModuleSecurityInfo from AccessControl.SecurityInfo import ModuleSecurityInfo
......
...@@ -16,5 +16,10 @@ ...@@ -16,5 +16,10 @@
If a request takes more than this value (in seconds), data connection can be terminated. If a request takes more than this value (in seconds), data connection can be terminated.
</description> </description>
</key> </key>
<key name="activity-timeout" required="no" datatype="integer">
<description>
If an activity takes more than this value (in seconds), data connection can be terminated.
</description>
</key>
</sectiontype> </sectiontype>
</component> </component>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment