Commit ef313964 authored by Vincent Pelletier's avatar Vincent Pelletier

CMFActivity.Activity.SQLBase: Tolerate group_id set without a grouping_method_id.

While it does not make sense, it is possible to spawn activities with a
group_id set but without a grouping_metohd_id. This is for example easy to
trigger using recurseCallMethod from ERP5Type.Core.Folder: the
_recurseCallMethod activity spawned nullifies grouping_method_id but does
not (currently) clean group_id, leading to inconsistency between how
"non-groupped" conditions are evaluated in getProcessableMessageList and
dequeueMessage.
The consequence is zombie activities: they never fail, do not prevent other
activities from being executed, but and are permanently run on the node
which reserved more than one because:
- all but one activity is in MESSAGE_NOT_EXECUTED state, forcing an abort
- finalizeMessageExecution does not understand that MESSAGE_NOT_EXECUTED
  activities may not have failed, and itself fail while trying to detect
  the failure type (ConflictError vs. others), failing to free & postpone
  the activity, in turn failing to bring it to eventually permanent failure
  state.
Make those conditions consistent, and use tuple-unpacking to detect any
future inconsistency much earlier, simplifying debugging.
parent 8777cc47
...@@ -551,7 +551,7 @@ CREATE TABLE %s ( ...@@ -551,7 +551,7 @@ CREATE TABLE %s (
message_list = [m] message_list = [m]
uid_to_duplicate_uid_list_dict[uid] = uid_list uid_to_duplicate_uid_list_dict[uid] = uid_list
group_method_id = m.line.group_method_id group_method_id = m.line.group_method_id
if group_method_id != '\0': if group_method_id[0] != '\0':
# Count the number of objects to prevent too many objects. # Count the number of objects to prevent too many objects.
cost = m.activity_kw.get('group_method_cost', .01) cost = m.activity_kw.get('group_method_cost', .01)
assert 0 < cost <= 1, (self.sql_table, uid) assert 0 < cost <= 1, (self.sql_table, uid)
...@@ -632,8 +632,8 @@ CREATE TABLE %s ( ...@@ -632,8 +632,8 @@ CREATE TABLE %s (
activity_runtime_environment = ActivityRuntimeEnvironment(None) activity_runtime_environment = ActivityRuntimeEnvironment(None)
else: else:
method = activity_tool.invoke method = activity_tool.invoke
message = message_list[0] message, = message_list
args = (message, ) args = message_list
activity_runtime_environment = ActivityRuntimeEnvironment(message) activity_runtime_environment = ActivityRuntimeEnvironment(message)
# Commit right before executing messages. # Commit right before executing messages.
# As MySQL transaction does not start exactly at the same time as ZODB # As MySQL transaction does not start exactly at the same time as ZODB
......
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