-
Bug
-
Resolution: Unresolved
-
Minor
-
None
-
4.1.15
-
MOODLE_401_STABLE
Under certain circumstances the paged_content_paging_bar handler for SET_ITEMS_PER_PAGE_LIMIT causes an utter waste of resources due to multiple calls to the server.
The main problem was detected in block_myoverview. The problem arises under specific circumstances, but is actually caused by subsequent calls to "initializePagedContent()" in block_myoverview/view.js
This method call in turn calls "PagedContentFactory.createWithLimit()".
The underlying problem is that ultimately, this initializes the paging_bar to subscribe to changes in the items per page using PubSub.subscribe(id + PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT, function(limit)
Unfortunately this causes an increasing number of identical calls to the server to load data and thus, not only an absolute waste of server resources, but also severe slowing down of the browser from the enduser's perspective.
The main issue is that the paging_bar does not unsubscribe the "original" callback.
Even if there would be an attempt to unsubscribe from PubSub, it would fail horribly. Reason being that the callback is an anonymous function and PubSub's unsubscribe suffers from the exact same problem pure JS "removeEventListener" has: the check for a callback is done using an identical check.
To reproduce:
- navigate to mycourses page (make sure there's a substantial range of courses, e.g. 50 of them)
- Open your browser's inspector, navigate to the network tab.
- Navigate to the next page in your mycourses block once or twice
- Verify that for each time you navigate, only one call to core_course_get_enrolled_courses_by_timeline_classification is performed.
- Perform a random search and await result
- Verify only a single call to core_course_get_enrolled_courses_by_timeline_classification is performed
- Clear search and await result
- Verify only a single call to core_course_get_enrolled_courses_by_timeline_classification is performed
- Change items per page to be different from the current one
- Instantly verify that "suddenly", multiple calls to core_course_get_enrolled_courses_by_timeline_classification are performed, all with the same criteria:
You can now do this search/clear search/change items per page trick a few times more and verify that the calls keep on stacking and stacking, ultimately making the page load slower and slower and....
Possible solution:
Add a clear() method to pubsub.js, as in:
/**
|
* Clear subscribed events.
|
*
|
* This is a patch solution since unsubscribing doesn't work with anonymous functions.
|
* This clears all registrations in provided event space and should be used when your
|
* implementation is certain to work "isolated", aka the event space is unique/atomic/isolated.
|
*
|
* @param {string} eventName The name of the event to remove all subscribtions from.
|
*/
|
export const clear = function(eventName) { |
delete(events[eventName]);
|
};
|
Modify registerEventListeners implementation in paged_content_paging_bar.js to clear() PubSub subscriptions, as in:
PubSub.clear(id + PagedContentEvents.ALL_ITEMS_LOADED);
|
PubSub.clear(id + PagedContentEvents.PAGES_SHOWN);
|
PubSub.clear(id + PagedContentEvents.SET_ITEMS_PER_PAGE_LIMIT);
|
|
Please note I've marked Moodle 4.1.15 as affected version, although it affects every branch since 3.6.0, including the current state of the repository.