Skip to content
Snippets Groups Projects
Commit ec0c0f29 authored by Martin Trigaux's avatar Martin Trigaux
Browse files

[IMP] gamification: performance improvement

Reduce the number of goals that are recomputed. Remove the goals for users that
did not connect since the last update.
Add sql query for faster lookup and restrict on user table
parent fb8dc579
No related branches found
No related tags found
No related merge requests found
...@@ -300,18 +300,23 @@ class gamification_challenge(osv.Model): ...@@ -300,18 +300,23 @@ class gamification_challenge(osv.Model):
goal_obj = self.pool.get('gamification.goal') goal_obj = self.pool.get('gamification.goal')
# we use yesterday to update the goals that just ended # include yesterday goals to update the goals that just ended
# exclude goals for users that did not connect since the last update
yesterday = date.today() - timedelta(days=1) yesterday = date.today() - timedelta(days=1)
goal_ids = goal_obj.search(cr, uid, [ cr.execute("""SELECT gg.id
('challenge_id', 'in', ids), FROM gamification_goal as gg,
'|', gamification_challenge as gc,
('state', '=', 'inprogress'), res_users as ru
'&', WHERE gg.challenge_id = gc.id
('state', 'in', ('reached', 'failed')), AND gg.user_id = ru.id
'|', AND gg.write_date < ru.login_date
('end_date', '>=', yesterday.strftime(DF)), AND gg.closed IS false
('end_date', '=', False) AND gc.id IN %s
], context=context) AND (gg.state = 'inprogress'
OR (gg.state = 'reached'
AND (gg.end_date >= %s OR gg.end_date IS NULL)))
""", (tuple(ids), yesterday.strftime(DF)))
goal_ids = cr.fetchall()
# update every running goal already generated linked to selected challenges # update every running goal already generated linked to selected challenges
goal_obj.update(cr, uid, goal_ids, context=context) goal_obj.update(cr, uid, goal_ids, context=context)
......
...@@ -268,6 +268,25 @@ class gamification_goal(osv.Model): ...@@ -268,6 +268,25 @@ class gamification_goal(osv.Model):
return {'to_update': True} return {'to_update': True}
return {} return {}
def _get_write_values(self, cr, uid, goal, new_value, context=None):
"""Generate values to write after recomputation of a goal score"""
if new_value == goal.current:
# avoid useless write if the new value is the same as the old one
return {}
result = {goal.id: {'current': new_value}}
if (goal.definition_id.condition == 'higher' and new_value >= goal.target_goal) \
or (goal.definition_id.condition == 'lower' and new_value <= goal.target_goal):
# success, do no set closed as can still change
result[goal.id]['state'] = 'reached'
elif goal.end_date and fields.date.today() > goal.end_date:
# check goal failure
result[goal.id]['state'] = 'failed'
result[goal.id]['closed'] = True
return result
def update(self, cr, uid, ids, context=None): def update(self, cr, uid, ids, context=None):
"""Update the goals to recomputes values and change of states """Update the goals to recomputes values and change of states
...@@ -281,14 +300,8 @@ class gamification_goal(osv.Model): ...@@ -281,14 +300,8 @@ class gamification_goal(osv.Model):
commit = context.get('commit_gamification', False) commit = context.get('commit_gamification', False)
goals_by_definition = {} goals_by_definition = {}
all_goals = {}
for goal in self.browse(cr, uid, ids, context=context): for goal in self.browse(cr, uid, ids, context=context):
if goal.state in ('draft', 'canceled'):
# draft or canceled goals should not be recomputed
continue
goals_by_definition.setdefault(goal.definition_id, []).append(goal) goals_by_definition.setdefault(goal.definition_id, []).append(goal)
all_goals[goal.id] = goal
for definition, goals in goals_by_definition.items(): for definition, goals in goals_by_definition.items():
goals_to_write = dict((goal.id, {}) for goal in goals) goals_to_write = dict((goal.id, {}) for goal in goals)
...@@ -313,8 +326,10 @@ class gamification_goal(osv.Model): ...@@ -313,8 +326,10 @@ class gamification_goal(osv.Model):
# the result of the evaluated codeis put in the 'result' local variable, propagated to the context # the result of the evaluated codeis put in the 'result' local variable, propagated to the context
result = cxt.get('result') result = cxt.get('result')
if result is not None and type(result) in (float, int, long): if result is not None and type(result) in (float, int, long):
if result != goal.current: goals_to_write.update(
goals_to_write[goal.id]['current'] = result self._get_write_values(cr, uid, goal, result, context=context)
)
else: else:
_logger.exception(_('Invalid return content from the evaluation of code for definition %s') % definition.name) _logger.exception(_('Invalid return content from the evaluation of code for definition %s') % definition.name)
...@@ -356,8 +371,9 @@ class gamification_goal(osv.Model): ...@@ -356,8 +371,9 @@ class gamification_goal(osv.Model):
queried_value = queried_value[0] queried_value = queried_value[0]
if queried_value == query_goals[goal.id]: if queried_value == query_goals[goal.id]:
new_value = user_value.get(field_name+'_count', goal.current) new_value = user_value.get(field_name+'_count', goal.current)
if new_value != goal.current: goals_to_write.update(
goals_to_write[goal.id]['current'] = new_value self._get_write_values(cr, uid, goal, new_value, context=context)
)
else: else:
for goal in goals: for goal in goals:
...@@ -379,26 +395,14 @@ class gamification_goal(osv.Model): ...@@ -379,26 +395,14 @@ class gamification_goal(osv.Model):
else: # computation mode = count else: # computation mode = count
new_value = obj.search(cr, uid, domain, context=context, count=True) new_value = obj.search(cr, uid, domain, context=context, count=True)
# avoid useless write if the new value is the same as the old one goals_to_write.update(
if new_value != goal.current: self._get_write_values(cr, uid, goal, new_value, context=context)
goals_to_write[goal.id]['current'] = new_value )
for goal_id, value in goals_to_write.items(): for goal_id, value in goals_to_write.items():
if not value: if not value:
continue continue
goal = all_goals[goal_id] self.write(cr, uid, [goal_id], value, context=context)
# check goal target reached
if (goal.definition_id.condition == 'higher' and value.get('current', goal.current) >= goal.target_goal) \
or (goal.definition_id.condition == 'lower' and value.get('current', goal.current) <= goal.target_goal):
value['state'] = 'reached'
# check goal failure
elif goal.end_date and fields.date.today() > goal.end_date:
value['state'] = 'failed'
value['closed'] = True
if value:
self.write(cr, uid, [goal.id], value, context=context)
if commit: if commit:
cr.commit() cr.commit()
return True return True
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment