Rails 3 - Cache Web Service Call

In my application, in the action of the main page, I call a specific web service that returns JSON.

parsed = JSON.parse(open("http://myservice").read) @history = parsed['DATA'] 

This data will not change more than once every 60 seconds and will not change for each visitor, so I would ideally like to cache the @history variable (since parsing does not lead to a new result) and automatically cancel it if it more than a minute.

I do not know how to do that. By default, Rails caching methods seem to be more focused on content that must be expired manually. I'm sure there is a quick and easy way to do this, I just don’t know what it is!

+4
source share
3 answers

You can use the built-in Rails cache to do this:

 @history = Rails.cache.fetch('parsed_myservice_data', :expires_in => 1.minute) do JSON.parse connector.get_response("http://myservice") end 

One of the problems with this approach is that recovering cached data takes quite a while. If during this time you receive many client requests, each of them will receive a missed cache and call your block, which will lead to a lot of duplicated efforts, not to mention the slow response time.

EDIT: In Rails 3.x, you can pass the :race_condition_ttl option to the fetch method to avoid this problem. Read more about it here .

A good solution for previous versions of Rails is to set the background / cron job, which should be run at regular intervals, which will retrieve and analyze data and update the cache.

In your controller or model:

 @history = Rails.cache.fetch('parsed_myservice_data') do JSON.parse connector.get_response("http://myservice") end 

In the background / cron job:

 Rails.cache.write('parsed_myservice_data', JSON.parse connector.get_response("http://myservice")) 

Thus, your client requests will always receive fresh cached data (except for the first request if the background / cron job is not already running.)

+6
source

I do not know how to do that. Maybe you should take a look at using redis. Redis allows you to set the expiration time of the data stored in it. Depending on which redis gem you are using, it looks something like this:

 @history = $redis.get('history') if not @history @history = JSON.parse(open("http://myservice").read)['DATA'] $redis.set('history', @history) $redis.expire('history', 60) end 

Since only one redis service will work for all your rails processes.

+1
source

We had a similar requirement, and we ended up using Squid as a direct proxy for all webservice calls from the rails server. Squid had a cache expiration time of 60 seconds.

http_connection_factory.rb:

 class HttpConnectionFactory def self.connection AppConfig.use_forward_proxy ? Net::HTTP::Proxy(AppConfig.forward_proxy_host, AppConfig.forward_proxy_port) : Net::HTTP end end 

In the action of your application home page, you can use a proxy instead of a direct call.

 connector = HttpConnectionFactory.connection parsed = JSON.parse(connector.get_response("http://myservice")) @history = parsed['DATA'] 

We thought about using Redis or Memcache . But we had several service calls, and we wanted to avoid all the problems with key generation and sweep them at the appropriate time.

So, in our case, the direct proxy server took care of all these worthless make-ups. Please refer to the Squid Wiki for the necessary configuration options.

0
source

Source: https://habr.com/ru/post/1369604/


All Articles