Commit 653ff194 authored by Julien Muchembled's avatar Julien Muchembled

simulation: remove all activity dependencies for indexation of 'delivery' category

They were useless since 'delivery' is indexed in ZODB, and this also fixes
a bug causing local build to fail in the following conditions:
- root document moved to a state that triggers a builder,
  whereas there's no simulation tree yet
- the builder select method has a condition on the root simulation movement

An example is building of task reports, when the ERP is overloaded.

The reason was that in some cases, ERP5 tried to set 2 tags on the same
reindexing activity (built: in updateMovementCollection & expand: in
_updateSimulation), but there's actually no support for multi-valued tags
and for CMFActivity, default activate parameters (here expand:) have lower
precedence (see ActivateObject.activate). So another possible fix is to add
built: to _localBuild after_tag.

This commit also renames expand: into build:
parent e8c3c849
......@@ -55,7 +55,7 @@ try:\n
delivery.aq_explicit.getCausalityState\n
except AttributeError:\n
return\n
delivery.activate(tag=\'expand:\'+delivery.getPath()).Delivery_calculate()\n
delivery.activate(tag=\'build:\'+delivery.getPath()).Delivery_calculate()\n
</string> </value>
</item>
<item>
......
......@@ -363,8 +363,7 @@ class Delivery(XMLObject, ImmobilisationDelivery, SimulableMixin,
if calculate:
path = self.getPath()
self.activate(
# after_tag to built: could be removed
after_tag=('built:'+path, 'expand:'+path),
after_tag='build:'+path,
after_path_and_method_id=(path, '_localBuild'),
).updateCausalityState()
if kw:
......@@ -683,11 +682,7 @@ class Delivery(XMLObject, ImmobilisationDelivery, SimulableMixin,
after_tag = [after_tag]
else:
after_tag = list(after_tag) if after_tag else []
# Now that 'delivery' category relation are indexed in ZODB, this is the
# only method that depends on built: tag (via _updateSimulation), which
# is still required because builders only use catalog to find buildable
# movements and we don't want to miss any for local building.
after_tag.append('expand:' + self.getPath())
after_tag.append('build:' + self.getPath())
sm = getSecurityManager()
newSecurityManager(None, nobody)
try:
......
......@@ -141,7 +141,7 @@ class SimulatedDeliveryBuilder(BuilderMixin):
"""
delivery = delivery_movement.getExplanationValue()
simulation_movement.recursiveReindexObject(activate_kw=dict(
activate_kw or (), tag='built:'+delivery.getPath()))
activate_kw or (), tag='build:'+delivery.getPath()))
BuilderMixin._setDeliveryMovementProperties(
self, delivery_movement,
simulation_movement, property_dict,
......
......@@ -169,28 +169,18 @@ class MovementCollectionUpdaterMixin:
movement.edit(**kw)
for property_id in kw:
movement.clearRecordedProperty(property_id)
movement_list = movement_diff.getNewMovementList()
if not movement_list:
return
if context.isRootAppliedRule():
reindex_kw = {'activate_kw': {
'tag': 'built:' + context.getCausalityValue().getPath()}}
else:
reindex_kw = None
def newMovement(kw={}):
return context.newContent(portal_type=self.movement_type,
reindex_kw=reindex_kw, **kw)
for movement in movement_list:
for movement in movement_diff.getNewMovementList():
d = movement.__dict__
assert movement.isTempObject()
if '_original' in d:
# slow but safe way (required for compensated movements)
newMovement(_getPropertyAndCategoryList(movement))
context.newContent(portal_type=self.movement_type,
**_getPropertyAndCategoryList(movement))
continue
# fast way (we had to make sure such optimization
# does not touch existing persistent data)
del movement.__dict__
movement = newMovement()
movement = context.newContent(portal_type=self.movement_type)
d.update(movement.__dict__)
categories = d.pop('categories')
movement.__dict__ = d
......
......@@ -505,10 +505,7 @@ class SimulableMixin(Base):
self.activate(
activity='SQLQueue',
group_method_id='portal_rules/updateSimulation',
tag='expand:' + path,
# Now that we don't rely on catalog anymore, this after_tag could
# moved to _localBuild, which currently only depends on 'expand:'.
after_tag='built:'+ path,
tag='build:' + path,
priority=3,
)._updateSimulation(**kw)
del tv[key]
......@@ -537,7 +534,7 @@ class SimulableMixin(Base):
if applied_rule is None:
applied_rule = self._createRootAppliedRule()
expand_root = applied_rule is not None
activate_kw = {'tag': 'expand:'+self.getPath()}
activate_kw = {'tag': 'build:'+self.getPath()}
if expand_root:
applied_rule.expand(activate_kw=activate_kw)
else:
......
......@@ -713,28 +713,18 @@ return context.generatePredicate(
self.assertEqual(line, sm.getDeliveryValue())
def test_14_indexRelated(self):
"""Check that simulation is indexed before being updated
"""Check that simulation can be updated even if a SM is not indexed yet
It is important that an update of a simulation tree is able to find all
related simulation movements, otherwise the following happens:
node 1 node 2
start first indexing of SM ...
change simulation state of PL
update simulation (no SM found)
commit result of indexing
-> SM has wrong simulation state
This actually tests the zodb-indexing of delivery category.
"""
root_applied_rule = self._slowReindex()
self.portal.portal_activities.distribute()
self.portal.cmf_activity_sql_connection.manage_test('delete from message')
self.pl.updateSimulation(index_related=1)
self.commit()
# this should distribute nothing as long as the indexing activity
# is not processed
self.portal.portal_activities.distribute()
r, = self.portal.cmf_activity_sql_connection.manage_test(
'select * from message_queue')
self.assertEqual(r.method_id, '_updateSimulation')
self.assertEqual(r.processing_node, -1)
self.tic()
sm, = root_applied_rule.objectValues()
line, = self.pl.getMovementList()
self.assertEqual([sm], [x.getObject() for x in self.portal.portal_catalog
.unrestrictedSearchResults(delivery_uid=line.getUid())])
def test_suite():
......
......@@ -757,6 +757,36 @@ class TestTask(TestTaskMixin, ERP5TypeTestCase):
finally:
portal_type.setTypePropertySheetList(original_property_sheet_list)
def test_08_localBuild(self):
sequence = Sequence(context=self)
sequence("""
Login
CreateOrganisation
CreateOrganisation
CreateResource
CreateProject
CreateRequirement
CreateSimpleTask
CreateCurrency
FillTaskWithData
SetTaskPriceCurrency
Tic
ConfirmTask
""")
self.tic(stop_condition=lambda message_list: all(
m.method_id != '_updateSimulation' for m in message_list))
rar, = sequence['task'].getCausalityRelatedValueList()
sm, = rar.objectValues()
q = self.portal.cmf_activity_sql_connection.manage_test
q('update message set processing_node=-4'
' where method_id="_localBuild" or path=%r' % sm.getPath())
self.commit()
self.portal.portal_activities.process_timer(None, None)
q('update message set processing_node=-1,'
' priority=method_id!="_localBuild"')
sequence("Tic SetTaskReport")
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestTask))
......
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