0

I have a rails application where I'm displaying charts using the gridList library. The chart data is fetched from a controller method (in JSON format) asynchronously using AJAX. When the page is loaded initially, each gridlist item shows loading icon and at the same time ajax call is made to the server to fetch the data. Each individual grid item makes a seperate ajax call. The charts are being rendered properly but the issue is that while the AJAX calls are ongoing, the server does not respond to any other requests like refreshing the page or changes in routes. It get blocked until all the charts are loaded, after which the previously called action occurs.

It is a server side issue as the javascript code on front-end works fine while the AJAX call is ongoing.

The grid items are rendered using the partial shown below

%li.grid_item{ data: { id: chart.id } }
 .chart-loading
   // loading icon
 .chart-content.hide
   // chart-content currently hidden.

:javascript
 var chart_id = "#{chart.id}"
 $.ajax({
   url: "#{get_data_charts_path(chart.id)}",
   success: function (res) {
     var data = JSON.parse(res)
     hideLoadingChart(chart_id) // hides loading and shows chart-content
     renderChart(data) // plots chart for the data
   }
 })

And the partial is called using the following command -

.grid-container
 %ul#grid.grid
  = render partial: 'chart', collection: @current_user.get_charts

What could be the problem. Is there a way to cancel all the current AJAX calls when a new request is made to the server.
Is this design where I'm making multiple AJAX calls for each chart correct. I want the charts to load as and when the data is available and not all at once in the end.

2 Answers2

1

A multi threaded server doesn't necessarily mean that requests are handled parallel.

Using multiple AJAX request to load data is not necessarily the problem (it does introduce some overhead), however if you need to load overlapping resources/records to answer each request you might want to ask yourself the question: "Why not load all data points in a single request?" You could for example use an index request and provide the boundaries of the data points, returning only the data points between the boundaries as JSON.

In your case you could load all data points by sending a request to GET /users/:user_id/charts.json to request all charts of one user. Assuming you have the route:

resources :users, only: [] do
  resources :charts, only: :index
end

Other possible solutions to speed up requests are:

  1. Optimize database queries (n + 1) problem, by using #includes when fetching from the database. You can easily see if this is a problem by looking at the server log.
  2. Optimize your heavy calculations by using lightweight algorithms. This is less easy to spot. If you request takes a long time but doesn't execute a lot of SQL queries you might want to plop down a few break points and see where all the time goes by jumping from break point to break point and get a feel how long things take. In some cases you can shove those calculations to the database by grouping, summing, taking averages etc.
  3. Assign more resources to your server, this speeds up the request handling. You could assign more than one worker to handle parallel requests, or assign more threads to handle requests faster. eg. bundle exec puma --workers 3 --threads 0:16 (0:16) is the default, passing a worker count higher than one will activate cluster mode (see bundle exec puma --help).
  4. Upgrade the hardware of the development machine. A better CPU or SSD might speed things up.
  5. Use a load balancer like NGINX to balance the load across multiple machines.
3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
0

You can look into $.Deffered which can be used to chain multiple ajax calls to make them sequential. Your server will receive only one ajax call at a time and the next will be made after first one finishes. Your server will be free to respond to other requests.

Simranjit Singh
  • 384
  • 1
  • 6
  • you mean to say that I should make the next AJAX call after the prev one is complete. But that would be a waste of resources as I am using a multi-threaded web server. Also each AJAX call is time consuming. If they are loaded one by one it will take a long time. – Urmil Parikh Aug 06 '18 at 17:00