-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add necessary tooling for Open edX events #7
Conversation
2f3fba7
to
2251e2e
Compare
b10a93f
to
03d68bf
Compare
755f544
to
5d4e6fc
Compare
7f65d63
to
564f556
Compare
67c8323
to
d7879cd
Compare
d7879cd
to
e6c9f96
Compare
564f556
to
77874b9
Compare
e6c9f96
to
1f8a798
Compare
openedx_events/tooling.py
Outdated
""" | ||
Getter function used to get the Open edX Events version. | ||
""" | ||
return openedx_events.__version__ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@felipemontoya this is what I'm returning for spec version.
The OEP 41 says: is a mandatory field that refers to the version of CloudEvents. We have to use “1.0” to be spec-compliant.
In our case, we'd refer to openedx-events version, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of sending the version of the openedx_events library, but I would not like to mix it with the specversion of CloudEvents.
I'd rather leave specversion
alone as "1.0" to not mess around and send another field with the openedx events version.
For the new field I'm thinking events_version
, but it could be other key
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could also play off the source*
convention and call it sourcelib
or something, but I'm totally fine with events_version
as well.
77874b9
to
9842f9d
Compare
effffbb
to
0df3e69
Compare
9842f9d
to
5fc5ba5
Compare
0df3e69
to
c4738eb
Compare
de25a1f
to
cfa9741
Compare
), | ||
) | ||
|
||
validate_sender() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @felipemontoya! I hope you're doing great.
I found an interesting case while implementing the POC with the 8 events. When the platform sends the signal UNENROLL_DONE, sends an argument called skip_refund
. I thought it was not a big deal, I could send the argument as a keyword... but the problem is this validation -that was discussed in the naming ADR-:
We expect send calls to always send things over as keyword args, and throw an exception if we get any parameters that we don't expect, or any parameters that are missing, based on the constructor call to OpenEdxPublicSignal.
This prevents sending extra arguments not defined in the event definition. And skip_refund
is not part of the CourseEnrollment object so it doesn't make sense to include it in the CourseEnrollmentrData class.
Then what can we do? I was thinking about just checking that at least the arguments defined when instantiating the event are sent
, what do you think? This way we can actually send sender
when needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding of the spirit of the discussion we had in the naming ADR is that we precisely dont want to permit extra params. We want to make the events super explicit in what they are passing around.
In my opinion we have 2 options. We add skip_refund to make the event we are creating for unenroll an make it 100% compatible to the current unenroll_done
or we don't and we make an event that is not 100% compatible. This means we will add it to the core platform and it will co-exist with the current unenroll_done for a while until we can migrate things.
I'd be inclined to say that we should leave without skip_refund and send two events when skip_refund is false. One for the unenrollment and one for the refund.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean something like:
UNENROLL_DONE_WITH_REFUND
UNENROLL_DONE_WITHOUT_REFUND
And the receivers would be subscribed to both signals, right? I like the idea, but what if more extra arguments are needed in the future? How many variations will we need?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean something like:
UNENROLL_DONE-> this is the unenrollment event with skip_refund = true
REFUND -> this is what happens when skip_refunds = false
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I would do the following:
UNENROLL_DONE -> this event gets sent on any unenrollment whether or not there is a refund.
REFUND -> this event gets sent if skip_refunds = false.
In the case of a refund, you still want the unenroll message for anyone that cares about enrollments.
6822ed8
to
7ca8286
Compare
openedx_events/tooling.py
Outdated
""" | ||
return "<OpenEdxPublicSignal: {event_type}>".format(event_type=self.event_type) | ||
|
||
def get_signal_metadata(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments:
Defining Metadata in data.py
Can the metadata itself be another attrs
class that has well defined fields? This could live somewhere independently of the learning events.
Separating CloudEvents serialization specifics.
Let's keep the metadata here in a more natural Python form while it's in memory, and convert it to the serialized version in an explicit CloudEvents layer in the future, when that becomes relevant. In concrete terms, I think that just means that specversion
goes away at this layer (it's a fixed constant for CloudEvents), time becomes a UTC datetime
instead of a string, and events version might become a tuple of ints so that version comparisons don't have to worry about lexical ordering of strings (e.g. '0.9.0' vs. '0.10.0').
Message Queue version
This isn't something I think you need to do yet, but is the long term plan to make metadata
an optional param that's auto-generated in the case of a local send, but populated from a serialized message if the signal is transmitted over a message queue?
UUID?
The CloudEvent will eventually have a UUID. Is it useful to have it in this metadata as well?
Nit: "get" vs. "create/generate"
This is a nit, but for me, get
implies something is more or less staying the same and you're accessing it, while create
or generate
means that you're creating a new thing and handing it back.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there @ormsbee! I hope you're doing good!
I've updated the PR with your recommendations:
Defining Metadata in data.py
I've created this PR showing how I would do this
Separating CloudEvents serialization specifics.
I followed all your recommendations here.
Message Queue version
I think the best thing is to consider this use case already. If a Metadata object exists, then it's not generated. What do you think?
UUID?
I added an ID as part of the metadata object, based on what the OEP-41 said:
https://open-edx-proposals.readthedocs.io/en/latest/oep-0041-arch-async-server-event-messaging.html#id2
Nit: "get" vs. "create/generate"
Thanks for the comment! I fixed it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update: we fully adopted defining metadata in data.py
26ad85c
to
80ad2c0
Compare
2e2e532
to
071c741
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good work @mariajgrimaldi.
I think this PR already covered all the feedback and the current proposal for the tooling is very robust. On my opinion we are ready to merge this.
863e3de
to
e827c18
Compare
- Add signal class used to create events - Add metadata atrr class - Add metadata generator to class - Add argument validator to class - Override signal methods to recommend using the custom send_event
e827c18
to
4ed2f5e
Compare
source (str): logical source of an event. | ||
sourcehost (str): physical source of the event. | ||
time (datetime): timestamp when the event was sent. | ||
sourcelib (str): Open edX Events library version. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mariajgrimaldi: Hello Maria. It seems we went with a tuple instead of a string. I'm curious why we did that. I'm working on the event bus, which is going to need to send this metadata across the wire, so I may need to pass in a string and convert it back to a tuple, which will be a bit strange, but would make the type in this comment more correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@robrap Hello there, Robert. After some digging, I found this discussion I had with dave when this PR was open: #7 (comment) If you think there's room for improvement, let me know! -besides updating the docstring 😅 -
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, Maria. I'm updating in this PR: https://github.com/openedx/openedx-events/pull/168/files#r1083076265
Description:
This PR adds the tooling needed to create and trigger events in Open edX platform. This PR includes:
The overall implementation was discussed by members of the community in this PR: #4
JIRA:
https://edunext.atlassian.net/browse/PS2021-629?atlOrigin=eyJpIjoiODIwNDA5M2MxZGRlNGQ2NjhjNjJhZWIwNWZiNWNlYjUiLCJwIjoiaiJ9
Testing instructions:
Option 1: using PR #18
With the event
STUDENT_REGISTRATION_COMPLETED
:In your Open edX devstack
make lms-shell
pip install git+https://github.com/eduNEXT/openedx-events.git@MJG/events_definition#egg=events_definition
We'll add soon an example using our plugin openedx-basic-hooks!
Reviewers:
Merge checklist:
Post merge:
finished.
Author concerns: