SIENTIAPDE-2011: Compute query-time levels union / ignore_models_id intersection

Push level and model-exclusion filtering down to the Mongo query instead of
fetching the full notification_queue unfiltered on every run.

- Fix await ordering in load_notification_package so sending_configs (active
  receiver_groups) resolves before load_latest_data is called, letting the
  query filter be built from group data.
- Add _compute_query_time_filter: unions active groups' `levels` (falls back
  to the workflow's default filter if any group has no restriction, since
  that group wants every level) and intersects their `ignore_models_id`
  (a model is only safe to drop from the fetch if every active group
  ignores it).
- Add unit tests covering mixed groups, a model ignored by only one group
  (must not be excluded from the fetch), and the empty active-groups case.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Eduardo Rios
2026-09-14 11:46:19 -03:00
parent ff7b441140
commit 1711f3b0d1
2 changed files with 113 additions and 5 deletions

View File

@@ -32,16 +32,19 @@ async def test_run(workflow_mock, load_notification_package):
'base_data_filter': {'level': 'ERROR'},
}
# Await order is now: last_timestamp -> sending_configs -> notification_package
# (fixed ordering bug: sending_configs must resolve before load_latest_data is
# called, so its levels/ignore_models_id can feed the query-time filter).
workflow_mock.start_local_activity_method.side_effect = [
'2023-01-01 12:00:00',
[
{
'id': '1',
'id_r': '1',
}
],
[
{
'id_r': '1',
'id': '1',
}
],
]
@@ -158,7 +161,9 @@ async def test_run_has_data(workflow_mock, load_notification_package):
'mail_type': 'test_mail_type',
}
workflow_mock.start_local_activity_method.side_effect = ['2023-01-01 12:00:00', ['data'], []]
# sending_configs (awaited 2nd) is empty here on purpose, to exercise the
# early-return branch below regardless of notification_package having data.
workflow_mock.start_local_activity_method.side_effect = ['2023-01-01 12:00:00', [], ['data']]
output = await load_notification_package.run(input_data)
@@ -169,3 +174,62 @@ async def test_run_has_data(workflow_mock, load_notification_package):
}
workflow_mock.start_activity_method.assert_not_called()
def test_compute_query_time_filter_empty_active_groups(load_notification_package):
default_filter = {'level': 'ERROR'}
result = load_notification_package._compute_query_time_filter([], default_filter)
assert result == default_filter
def test_compute_query_time_filter_mixed_groups_no_levels_restriction(load_notification_package):
# One active group restricts levels/ignore_models_id, the other has neither set
# (the common case today) -> that group wants everything, so no levels
# restriction can be applied at query time; falls back to default_filter.
sending_configs = [
{'group_name': 'group_a', 'levels': ['ERROR'], 'ignore_models_id': ['model_a']},
{'group_name': 'group_b'},
]
default_filter = {'level': 'ERROR'}
result = load_notification_package._compute_query_time_filter(sending_configs, default_filter)
assert result == {'level': 'ERROR'}
def test_compute_query_time_filter_model_ignored_by_only_one_group_not_excluded(
load_notification_package,
):
# model_a is ignored by group_a but group_b still wants it -> must stay in
# the fetch (the per-group filter is what drops it for group_a specifically).
sending_configs = [
{'group_name': 'group_a', 'levels': ['ERROR'], 'ignore_models_id': ['model_a']},
{'group_name': 'group_b', 'levels': ['ERROR'], 'ignore_models_id': []},
]
default_filter = {}
result = load_notification_package._compute_query_time_filter(sending_configs, default_filter)
assert result == {'level': {'$in': ['ERROR']}}
assert 'model_id' not in result
def test_compute_query_time_filter_union_levels_and_intersection_models(
load_notification_package,
):
# Every active group restricts levels -> union of levels applies.
# model_a is ignored by every active group -> safe to exclude at query time.
sending_configs = [
{'group_name': 'group_a', 'levels': ['ERROR'], 'ignore_models_id': ['model_a', 'model_b']},
{'group_name': 'group_b', 'levels': ['WARNING', 'ERROR'], 'ignore_models_id': ['model_a']},
]
default_filter = {}
result = load_notification_package._compute_query_time_filter(sending_configs, default_filter)
assert result == {
'level': {'$in': ['ERROR', 'WARNING']},
'model_id': {'$nin': ['model_a']},
}