Proposed Events API discussion

Proposed Events API discussion

by Tim Hunt -
Number of replies: 22
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
This is something Martin D plans to introduce in Moodle 1.9. The description is here: http://docs.moodle.org/en/Development:Events. This document is very recent, and now is a good time to comment before work starts on implementing it.

In my opinion, it is a really cool concept. However, I wanted to query a few things, and I thought that this was the appropriate place to discuss it.


Comment 1 is about the database tables. Martin is proposing two: event_handlers and event_queue. This is not properly normalised, because if you have several handlers for one event, the same (potentially large) eventdata object will be repeated several rows.

We should have three tables: event_handlers as before, event_queued_events with columns id, eventdata, schedule and timecreated, and event_queue_handlers_todo, with columns id, queuedeventid, handlerid, status, timmodified.

When the last row in event_queue_handlers_todo referring to a row in event_queued_events is removed, then the corresponding row from event_queued_events is automatically removed.
Average of ratings: -
In reply to Tim Hunt

Re: Proposed Events API discussion

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
Comment 2 is about making it easier to debug problems, and is basically a request to add more data to the tables, which is why I thought it was worth normalising them properly.

In event_queued_events, I suggest we add columns

stackdump text serialized debug_backtrace showing where the event was fired from
userid int(10) $USER->id when the event was fired

Possibly some others. And possibly allow these to be null, and only store them if some config option is turned on.

In event_queue_handlers_todo (someone should think of a better name for this), add an column

errormessage text if an error happened last time we tried to process this event, record it here.


Or perhaps a better way to deal with all this is to have some sort of log table, which is what Martin suggests on the wiki page.

In reply to Tim Hunt

Re: Proposed Events API discussion

by Martin Dougiamas -
Picture of Core developers Picture of Documentation writers Picture of Moodle HQ Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers
About logging, I was thinking that we just add the logs to the existing "log" table (with specific fields to make it easier to isolate events).

A related notion that's been floating around is that of merging add_to_log into the whole thing, so that all the "events" we currently log suddenly become possible triggers. This would instantly create all kinds of possibilities for interesting handlers.

Storing a backtrace is a good idea.
In reply to Martin Dougiamas

Re: Proposed Events API discussion

by Mike Churchward -
Picture of Core developers Picture of Plugin developers Picture of Testers
After reading your question in the wiki about logs, and then reading this, it became apparent to me that the logging function should be a subsystem on its own that owns what the data structures look like. Activities that need to log actions shouldn't worry at all about what log table it goes into. That way, when you create new functions like this one, you don't have to think or care about whether its in a separate table (okay you actually do have to care, but only when you take off your event subsystem hat and put on your log subsystem hat).

Then, if it ever makes sense to separate out different types of logs into different types of tables, we can do that within the log subsystem. And, if we use the events to handle the log sub-system, the log sub-system can dispatch specific actions on specific events, possibly even throwing events out in case someone cares and is listening? (Hey! I just go a admin login failure! Anyone care?).

mike
In reply to Tim Hunt

Re: Proposed Events API discussion

by Martin Dougiamas -
Picture of Core developers Picture of Documentation writers Picture of Moodle HQ Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers
About the duplication of data in event_queue, my thoughts were to allow the data for each item in the queue to be independent (even though they will most likely always be the same for a particular trigger, it's nice to know they don't have to be). It keeps the model simpler which could be useful once these tables become heavily used. I'm a little hesitant about having to keep two tables in sync via PHP.

The queue should be pretty short or empty most of the time - it only holds events that have failed or are waiting for the next cron.

However, I don't mind changing it if there's strong support for the idea of three tables. The nice thing is that such things can easily be extended later, because it's entirely internal to the Events API and no crucial data is held in these tables.
In reply to Martin Dougiamas

Re: Proposed Events API discussion

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
You would not need to use PHP to keep the two tables in sync. At the end of the function that processes events, just do a

DELETE FROM event_queued_events WHERE id NOT IN (SELECT queuedeventid FROM event_queue_handlers_todo);
In reply to Tim Hunt

Re: Proposed Events API discussion

by Martín Langhoff -

I like the proposed design -- and in terms of the 2 vs 3 tables I tend to lean towards martinD's 2-tables, but I don't mind one way or the other.

A couple of notes:

  • I think that the API should allow anything in the serialised data (as it does), but that there should be super extra strong encouragement to put the actual data elsewhere. So for the example given in the wikipage, I'd put the data in the grades table and then trigger a (perhaps parameter-less) event that succintly says "new grades!".
  • I am not opposed to having support for "immediate" events as well as "queued" events. I do think that queued events is all we should ever use... no. About once a year, it's safe to commit code that needs immediate events... wink
  • The events that Moodle triggers will become a bespoke API -- should we maintain some doco on those, explanining how and when they are triggered?
  • How do we discourage cross-module interdependencies that the API will probably foster?

smile

Edit: I see now that 'timing' probably controls queued vs immediate.

In reply to Martín Langhoff

Re: Proposed Events API discussion

by Martin Dougiamas -
Picture of Core developers Picture of Documentation writers Picture of Moodle HQ Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers
Yep, the 'schedule' field is about timing. If a single assignment is graded then it makes sense to use 'instant', so the grade gets into the gradebook right away.

For less crucial stuff, or bulk stuff, then 'cron' make sense - in that case it'll be on the queue for up to the cron period (usually 15 minutes).
In reply to Martin Dougiamas

Re: Proposed Events API discussion

by Valery Fremaux -

Martin, you told me about Events for making cross-modules API. I read it out and wonder what is the processing path for 'instant' events.

My goal is making one module (some project dedicated module) ask for data to a potentially not installed module, and to bind such instance of a coursemodule to exacly such other instance, as they are fit to work (potentially) together. Another situation could be plugin a module within another so that part of its data model get shared with part of another. Say, when adding a task module (Jeff Graham's), I can bind that module to use a techproject task outline rather than its internal model, or even just some of the attributes.

As Events are essentially an asynchronous triggering method (seems trivial when croned, that cron framework will consume all queued events), I fear such very synchronous form of cooperation does not exactly fit, as this is not a straight implementation of the Observer pattern in that way I wonder how the triggered event can give data back to another module for displaying in its caller screen.

So my main question : when triggering out an "instant' event, what is the path ? How could I lock and wait for a synchronous answer (supposed it is an answering event) of the triggered module ? (e.g. in order to complete my output with the data I get from that anwser).

In case events are not exactly suited for this kind of cooperation, how to get a real synchronous Listener registration pattern ?

In reply to Martín Langhoff

Re: Proposed Events API discussion

by Dan Poltawski -
The prospect of slow-running immediate events scares me also.. It makes me wonder if there should be the ability to determine event handler run-times, and disable slow running handlers. (I just have a vision of slow running immediate events continually being triggered).
In reply to Tim Hunt

Re: Proposed Events API discussion

by Peter Ritter -
hi there,

this new concept seems to become a good help to us. we are working on a synchronization between Moodle and an external LMS.
We do have a working implementation. But we put our code into Moodle's core-code. Now we are working on changing our implementation to work as a module to be "update-resistant" wink
So we need our synchronise-activity-module to be informed of any changes on enrolled students or other basic course information (from Moodle), as well as information of new grades from the external LMS to be written into the Moodle-DB.
First we thought we could use some functionality similar to the Forum-force-subscription, but it seems to be very difficult because of some missing documentation on how this works.
But now we hope, this forthcoming events-API could reduce the complexity of our task.
Therefore I would like to know your opinion to this. do you agree?
And am I right that that the modules can react on either internal events (such as new enrolments or new groups to a course) or events from other modules (like new grades)?

I hope that this was the right place to post this question. I am thankful to any help or advice...

Peter
In reply to Peter Ritter

Re: Proposed Events API discussion

by Peter Ritter -
Perhaps I just point out that the term of an "external LMS" was not exactly what I meant.
The external system we are going to synchronize with is a third-party open-source mathematical learning tool named MUMIE. Students can work on exercises as applets. These exercises are graded automatically by the system and the grades should be send back to Moodle.
But the whole course, semester and user administration has to come from Moodle via synchronisation. (MUMIE still gots its own database)
In short: We want to integrate MUMIE to behave as a homework-tool into Moodle.
I hope now you get a better understanding of our project.
If there are still any questions or annotations - don's hesitate to write.


In reply to Peter Ritter

Re: Proposed Events API discussion

by Martin Dougiamas -
Picture of Core developers Picture of Documentation writers Picture of Moodle HQ Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers
Yes a new activity module still needs to be written so that it can be added as an activity in to courses. The LAMS module is probably the closest example to this, it's very similar in fact.

You can use any mechanism you like to copy grades from MUMIE to your module's tables, or enrolment information from Moodle to MUMIE (this is unrelated to the event API). Like Martin L said, there are lots of normal functions available to help find this information in Moodle.

The event API will only be important when you want to pump those grades into the gradebook, or trigger other events that might be interesting.

In reply to Martin Dougiamas

Re: Proposed Events API discussion

by Peter Ritter -
allright.....
thanks so far. I guess I should take a look at the LAMS module now.

I see, it is possible to get the relevant information (for example students in a course) with the available functions (like get_course_users).
But this functions have to be called out of the activity. Right?

Since we don't want the course-databases (Moodle's and MUMIE's) to be inconsistent, we would like to have any changes in our course (and not just the activity) like enrollments or new trainer or new groups automaticly send to the activity (and we then forward it to MUMIE).
And we are not quite sure how to tell Moodle to always send such information. (We are still trying to understand the force-subscription of the forum...)

And yes.. We do want to get the MUMIE grades to be in the gradebook later because one of our goals is that a student should use MUMIE as a part of Moodle not noticing he is redirected to another system.
In reply to Peter Ritter

Re: Proposed Events API discussion

by Martín Langhoff -
Hi Peter - I would suggest that you write a standard module for this. Focus on the main module API -- the events API will just be an extension of the module API. A module can use all the standard Moodle functions to ask about enrolment, groups, etc.
In reply to Tim Hunt

Re: Proposed Events API discussion

by sam marshall -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers

1) Why does the 'schedule' option in events_handlers only include 'cron' or 'instant'? How about allowing that to be a number in seconds (or 0=instant) for future expansion i.e. in case there is ever any attempt to shuffle load of cron, so that if the system has a lot of things to do in cron it can drop 'later' ones until next time? (Okay maybe this is not so important really...)

2) Where did the 'schedule' option in events_queue come from if the data is only stored once? (Some handlers might have cron, some might be instant.) There didn't seem to be any option to spec this when creating an event. I don't think it should be there (is this an intentional mistake to check I'm reading?)

3) Re events_queue_handlers; is there a number of times after which retry stops happening? Any logic so that retries become less frequent as the count increases? [What I'm really getting at is that it probably shouldn't keep retrying for ever, notifying somebody would be good!]

4) Should there be a way to define 'provided' events as well as 'requested' events? So that we can for example do debug checks that the requested events match up with those provided somewhere on the system.

(edit) AAAAND one more.

5) Event requests should contain a 'filter' parameter, optional, as serialised PHP object. The semantics of the filter would depend on the specific event. For example, imagine there is a role_assign event, but you only care about assign to courses; could be $filter->contextlevel=50. Events that support filters would need to be sent with a callback function that basically returns true or false depending on a $filter.

(edit) AAAAAND another one more

6) Should be a way to define events as 'overwrite' type i.e. an event supercedes other events of the same type/parameters (because it just notifies something has happened, without including any specific data). This allows for potential later performance improvements such as not adding any events to the queue if a previous similar event already caused all handlers to be added.

--sam

In reply to sam marshall

Re: Proposed Events API discussion

by Martin Dougiamas -
Picture of Core developers Picture of Documentation writers Picture of Moodle HQ Picture of Particularly helpful Moodlers Picture of Plugin developers Picture of Testers
Some quick jots from the airport!

1) It's a text field so we can we add more easily (arbitrarily even). Further optimisation in cron might be useful later ... I guess we can add that once we get more familiar with it.

2) This events_queue schedule gets copied from the events_handler ... it's a copy just in case we might want to alter it in the queue (override what the handler said it wanted) for some reason.

3) Yes indeed it would throw a "too many failed attempts" event. (we talked about it but it hadn't made the document yet, sorry. Fixed.).

4) To catch typos in event names, maybe, yes ... perhaps unit tests can do this?

5) Can't all that go in the main $eventdata object?

6) I can't think of an example where a module would send two events for the same thing this way ...
In reply to Martin Dougiamas

Re: Proposed Events API discussion

by sam marshall -
Picture of Core developers Picture of Peer reviewers Picture of Plugin developers
1,2,3 - OK.

4 - It would also provide psuedo-documentation (standard place to look for events and would be possible to automatically create a list of all available events in moodle, perhaps as an admin report [on which note - I kind of wonder if we need a 'developer' category of admin reports]). For checking, I was thinking along the lines of the check it does for whether capabilities exist, when debugging is turned to developer. I.e. when you send or request an event it checks it exists.

5 - You're right, it would be easier to just check it in the event function and ignore any you don't care about.

6 (ignoring duplicate events) - Well, I can smile However it may not apply. For example supposing there is a 'role assignments have changed on course x' event. It might be fairly frequent that this event would be sent say 500 times when students are allocated to the course, but really only needs to run once. HOWEVER it may be the intent that this kind of 'something's changed in the database, go look it up' event is never or not normally used and those examples would become 'user y has been added to course x' which would obviously not be repeated. That's certainly how the example works.

--sam
In reply to sam marshall

Re: Proposed Events API discussion

by Peter Ritter -
Hi there,

are such events just thrown my modules or from core-parts of Moodle, too? I am asking, because we are working on an activity-module that has to keep an external DB konsistant to Moodle's.
So even when such an activity has been put into a course, we want to be informed when for example a new group is created whithin that course.
Unfortunately there is no "if(function_exists..."-call for this situation and we do not want to make extensions to Moodle's core-code. So the possibility of triggering an event could eventually help us a lot.
What do you think??

Greetings
Peter
In reply to Peter Ritter

Re: Proposed Events API discussion

by Peter Ritter -
Hello again....

I got a question on where you are going to place the events_trigger()-calls... More high-level or more low-level...
An example for a better understanding:
We want to keep an external DB synchronized to Moodle's. So we need events triggered, when for example a course has been updated. So we would add an events_trigger()-call into moodle/course/edit.php (near line 111 in Moodle1.9). That's OK.
We do also want to know about groups. So when a group has been deleted we suggest to add an events_trigger()-call into moodle/group/edit.php (near line 86).
But what about a course that have been deleted? Before the course will be deleted all groups within this course will automaticly been deleted before. So should there be an events-trigger('group_deleted')-call in moodle/group/lib/basicgrouplib.php (in function groups_delete_group) or is this too low-level. Our third-party-software could cope with just the info about the deleted course, too. Then it would do exactly the same internal checks and delete-calls as Moodle does.
But what about a user that enrolls into a course via enrollment key that put the user into a group, too. Where to call the events_trigger('group_user_added') then?
What do you think?

Greetings...
Peter
In reply to Peter Ritter

Re: Proposed Events API discussion

by Subodh Iyengar -
Im working on a moodle project and this events API could be really useful. I wanted to ask 3 questions:
1) Is the message_send event implemented in Moodle 1.9.3?
2) Is the message_send event implemented for modules other than forum, and what are the other event names that are triggered for the modules, i.e. is there an event for 'add discussion'?
3) Is there a way to add a custom field to the event data that is thrown by a module. I need to add the id of the post also into the eventdata as a field.
In reply to Subodh Iyengar

Re: Proposed Events API discussion

by Mike Churchward -
Picture of Core developers Picture of Plugin developers Picture of Testers
The easiest way to find out what events are being triggers in the Moodle code is search through for all occurrences of "events_trigger". I think you'll find that "message_send" is not triggered.

mike
In reply to Mike Churchward

Re: Proposed Events API discussion

by Tim Hunt -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers
message_send is new in Moodle 2.0, I think.