Using Message Listener for reducing first byte and page load time

Page load optimization using Message Listener

Problem statement:

Liferay page can have many components like, ADTs, custom portlets, etc. The components having complex business logic, high-level back-end processes, or integration with external platforms, may take up a lot of time to reproduce the data that is to be rendered for the user. 
When a user logs into their website, the first impactful experience they have is the website performance, which is how much time it takes for the page to load and components to render. By default, all components are loaded serially, and if one of them takes up a lot of time to load, it will slow down all the other components, thus increasing the DOM, and delaying the user in interacting with the page.

Increase in page load time results in user abandoning the site, so good performance is a key asset in site building.

Initial Solution:

To resolve the issue, the custom portlets that are taking a lot of time to load, can be made Ajaxable. So, when the page is loading, the components taking less time to render, load first, and for Ajaxable portlets, Liferay renders a JavaScript code which fetches these portlets parallelly through Ajax call.

Issue with the initial solution and the resolution by using Message Listeners:

After implementing this change, while these Ajaxable portlets will not hold up the other components, if the business logic takes up a large amount of time, the slowness becomes quite visible to the user. This also increases the whole page load time since the API call starts after the other components on the page were loaded.

So, to resolve this issue, the processing of ‘time taking business logic’ can be started while the user logs in, so that, when the login process completes and user is redirected to their landing page, the custom logic can also provide the response data that is to be rendered in the Ajaxable portlet.

Consider the scenario that we are calling external APIs to fetch the user specific data to be rendered in some custom portlets. These portlets have been made Ajaxable and are present on the landing page with other fast performing custom components. These external APIs are taking a lot of time to return the successful response, so instead of calling these APIs from the Ajaxable portlets, the logic can be moved to a post login event. So now, when the user logs in, inside the custom logic for login in PostLoginAction, the API request is sent as a Message in Message Bus to the Destination. The Message Listener registered to that Destination listens to that message and calls the external API with that request. On receiving the response, they set it in session. Meanwhile, PostLoginAction has redirected to the landing page and the custom components have started loading. When the Ajaxable component starts to load, they check the session for the response, and on finding the data, it reads it, and then renders it for the user.

High-level view of using Message Listener during login to reduce page load time:
 

As shown in the image above, the API request is sent as a Message using Message Bus. 

Here is how Message can be created with Object Payload:


 

 Send the message directly using Message Bus to the destination:
 

Once the custom code in PostLoginAction is executed, the user is redirected to the homepage and all the components there start to load. Meanwhile, the message is sent to the destination.

Create DestinationConfiguration for parallel destinations:

While configuring the destination, it can be set as Parallel, Serial or Synchronous. Considering a system with multiple users logging in at similar time we are setting it as Parallel destination as it processes the messages asynchronously using multiple worker threads.
 


 

Setting Thread Pool for destination:

We can configure the maximum queue size, workers core size and maximum size.

Create the destination:

Add the destination to the OSGi service registry:

Track references to the destination service registrations:



Create the Message Listener for the destination:



Add the custom business logic in receive method:



Reading the response from session:


 

Conclusion:

On implementing these changes, the impact on performance of the site is quite visible as the time taking business logic is moved to Message Listener registered to the destination. By using Parallel destination, multiple worker threads from a thread pool, deliver the message to the Message Listener, so, there is no time spent in waiting for a process to complete before redirecting to a User Interactive view. The first byte, DOM as well as the whole page load time decreases, and the user also feels considerable fast load time thus making it a positive user experience.