Skip to content

Commit

Permalink
feat!: new event bus config format
Browse files Browse the repository at this point in the history
  • Loading branch information
Rebecca Graber committed Sep 26, 2023
1 parent c937fba commit 302389a
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 44 deletions.
49 changes: 34 additions & 15 deletions openedx_events/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ def general_signal_handler(sender, signal, **kwargs): # pylint: disable=unused-
"""
Signal handler for publishing events to configured event bus.
"""
configurations = getattr(settings, "EVENT_BUS_PRODUCER_CONFIG", {}).get(signal.event_type, ())
configurations = getattr(settings, "EVENT_BUS_PRODUCER_CONFIG", {}).get(signal.event_type, {})
event_data = {key: kwargs.get(key) for key in signal.init_data}
for configuration in configurations:
if configuration["enabled"]:

for topic in configurations.keys():
if configurations[topic]["enabled"]:
get_producer().send(
signal=signal,
topic=configuration["topic"],
event_key_field=configuration["event_key_field"],
topic=topic,
event_key_field=configurations[topic]["event_key_field"],
event_data=event_data,
event_metadata=kwargs["metadata"],
)
Expand All @@ -34,47 +35,65 @@ class OpenedxEventsConfig(AppConfig):

name = "openedx_events"

def _get_validated_signal_config(self, event_type, configurations):
def _get_validated_signal_config(self, event_type, configuration):
"""
Validate signal configuration format.
Example expected signal configuration:
{
"topic_a": { "event_key_field": "my.key.field", "enabled": True },
"topic_b": { "event_key_field": "my.key.field", "enabled": False }
}
Raises:
ProducerConfigurationError: If configuration is not valid.
"""
if not isinstance(configurations, list) and not isinstance(configurations, tuple):
if not isinstance(configuration, dict) and not isinstance(configuration, dict):
raise ProducerConfigurationError(
event_type=event_type,
message="Configuration for event_types should be a list or a tuple of dictionaries"
message="Configuration for event_types should be a dict"
)
try:
signal = OpenEdxPublicSignal.get_signal_by_type(event_type)
except KeyError as exc:
raise ProducerConfigurationError(message=f"No OpenEdxPublicSignal of type: '{event_type}'.") from exc
for configuration in configurations:
if not isinstance(configuration, dict):
for topic, topic_configuration in configuration.items():
print(f"{topic_configuration=}")
if not isinstance(topic_configuration, dict):
raise ProducerConfigurationError(
event_type=event_type,
message="One of the configuration object is not a dictionary"
message="One of the configuration objects is not a dictionary"
)
expected_keys = {"topic": str, "event_key_field": str, "enabled": bool}
expected_keys = {"event_key_field": str, "enabled": bool}
for expected_key, expected_type in expected_keys.items():
if expected_key not in configuration:
if expected_key not in topic_configuration.keys():
raise ProducerConfigurationError(
event_type=event_type,
message=f"One of the configuration object is missing '{expected_key}' key."
)
if not isinstance(configuration[expected_key], expected_type):
if not isinstance(topic_configuration[expected_key], expected_type):
raise ProducerConfigurationError(
event_type=event_type,
message=(f"Expected type: {expected_type} for '{expected_key}', "
f"found: {type(configuration[expected_key])}")
f"found: {type(topic_configuration[expected_key])}")
)
return signal

def ready(self):
"""
Read `EVENT_BUS_PRODUCER_CONFIG` setting and connects appropriate handlers to the events based on it.
Example expected configuration:
{
"org.openedx.content_authoring.xblock.deleted.v1" : {
"topic_a": { "event_key_field": "xblock_info.usage_key", "enabled": True },
"topic_b": { "event_key_field": "xblock_info.usage_key", "enabled": False }
},
"org.openedx.content_authoring.course.catalog_info.changed.v1" : {
"topic_c": {"event_key_field": "course_info.course_key", "enabled": True }
}
}
Raises:
ProducerConfigurationError: If `EVENT_BUS_PRODUCER_CONFIG` is not valid.
"""
Expand Down
19 changes: 11 additions & 8 deletions openedx_events/tests/test_producer_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,31 +78,34 @@ def test_configuration_is_validated(self):
with pytest.raises(ProducerConfigurationError, match="should be a dictionary"):
apps.get_app_config("openedx_events").ready()

with override_settings(EVENT_BUS_PRODUCER_CONFIG={"invalid.event.type": []}):
with override_settings(EVENT_BUS_PRODUCER_CONFIG={"invalid.event.type": {}}):
with pytest.raises(ProducerConfigurationError, match="No OpenEdxPublicSignal of type"):
apps.get_app_config("openedx_events").ready()

with override_settings(EVENT_BUS_PRODUCER_CONFIG={"org.openedx.content_authoring.xblock.deleted.v1": ""}):
with pytest.raises(ProducerConfigurationError, match="should be a list or a tuple"):
with pytest.raises(ProducerConfigurationError, match="should be a dict"):
apps.get_app_config("openedx_events").ready()

with override_settings(EVENT_BUS_PRODUCER_CONFIG={"org.openedx.content_authoring.xblock.deleted.v1": [""]}):
with pytest.raises(ProducerConfigurationError, match="object is not a dictionary"):
with override_settings(EVENT_BUS_PRODUCER_CONFIG={"org.openedx.content_authoring.xblock.deleted.v1":
{"topic": ""}}):
with pytest.raises(ProducerConfigurationError, match="One of the configuration objects is not a"
" dictionary"):
apps.get_app_config("openedx_events").ready()

with override_settings(
EVENT_BUS_PRODUCER_CONFIG={
"org.openedx.content_authoring.xblock.deleted.v1": [{"topic": "some", "enabled": True}]
"org.openedx.content_authoring.xblock.deleted.v1": {"some": {"enabled": True}}
}
):
with pytest.raises(ProducerConfigurationError, match="missing 'event_key_field' key."):
apps.get_app_config("openedx_events").ready()

with override_settings(
EVENT_BUS_PRODUCER_CONFIG={
"org.openedx.content_authoring.xblock.deleted.v1": [
{"topic": "some", "enabled": 1, "event_key_field": "some"}
]
"org.openedx.content_authoring.xblock.deleted.v1":
{
"some": {"enabled": 1, "event_key_field": "some"}
}
}
):
with pytest.raises(
Expand Down
29 changes: 8 additions & 21 deletions test_utils/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,28 +30,15 @@

SECRET_KEY = "not-so-secret-key"
EVENT_BUS_PRODUCER_CONFIG = {
'org.openedx.content_authoring.xblock.published.v1': (
'org.openedx.content_authoring.xblock.published.v1':
{
'topic': 'content-authoring-xblock-lifecycle',
'event_key_field': 'xblock_info.usage_key',
'enabled': True
'content-authoring-xblock-lifecycle': {'event_key_field': 'xblock_info.usage_key', 'enabled': True},
'content-authoring-all-status': {'event_key_field': 'xblock_info.usage_key', 'enabled': True},
'content-authoring-xblock-published': {'event_key_field': 'xblock_info.usage_key', 'enabled': False}
},
'org.openedx.content_authoring.xblock.deleted.v1':
{
'topic': 'content-authoring-all-status',
'event_key_field': 'xblock_info.usage_key',
'enabled': True
},
{
'topic': 'content-authoring-xblock-published',
'event_key_field': 'xblock_info.usage_key',
'enabled': False
},
),
'org.openedx.content_authoring.xblock.deleted.v1': (
{
'topic': 'content-authoring-xblock-lifecycle',
'event_key_field': 'xblock_info.usage_key',
'enabled': True
},
),
'content-authoring-xblock-lifecycle': {'event_key_field': 'xblock_info.usage_key', 'enabled': True},
}
}

0 comments on commit 302389a

Please sign in to comment.