Rails cache blocks client requests during creation

Preventing query blocking by caching and automatically recovering fresh caches

We can easily create a Rails cache and set an expiration time like this

 Rails.cache.fetch(cache_key, expires_in: 1.minute) do `fetch_data_from_mongoDB_with_complex_query` end 

Somehow, when a new request arrives, the validity period expires and the request is blocked. My question is: how can I avoid this situation? Basically, I want to provide the previous cache to the client request, while Rails does the cache.

As shown in the expected behavior diagram, the second request will receive cache 1 but not cache 2 , although Rails does for cache 2 . Thus, the user does not have to spend a lot of time creating a new cache. So, how can I automatically restore all caches without prompting the user to invoke it?

Expected Behavior

Cache snippet

  cache_key = "#{__callee__}" Rails.cache.fetch(cache_key, expires_in: 1.hour) do all.order_by(updated_at: -1).limit(max_rtn_count) end 

Update

How can I get all cached keys in a command?

Since a cached request can be generated by the composition start_date , end_date , depature_at , arrive_at .

Unable to invalidate all cached keys manually.

How can I get all cache keys and then update in Rake task

+6
source share
2 answers

Using expiration difficult, once the cached object expires, you cannot retrieve the value you are looking for.

The best practice is to disable the cache update process from end-user traffic. You will need a rake task that populates / updates your cache and runs this task as cron. If for some reason the task fails, the cache expires and your users get extra time to retrieve the data.

However, if your data set is too large to update / load all at once, you will have to use a different cache expiration policy (you can update the expiration time after each cache hit).

Alternatively, you can disable cache expiration and use a different indicator (for example, time) to determine if the cache object is current or outdated. If it's out of date, you can use the asynchronous ActiveJob worker to queue the job to update the cache. Outdated data will be returned to the user, and the cache will be updated in the background.

+2
source

It seems to work like caching is designed to work. When the second request arrives, after 1hr in your case, the request restarts and blocks the request during the execution of the request.

You want Rails to return cache1 original expired while it worked on creating a new cache2 .

But think about what you ask? Are you asking him to return what has expired? How rails can return cache1 when it expired. This happened because you explicitly set the cache expiration date exactly 1 hour later.

There are many ways to achieve what you want, here is one solution that immediately comes to mind:

  • Run your long query and put its result along with the current timestamp in your cache. Do not leave any guarantees on it.
  • Schedule a background job to restart the query cache and upgrade to 1 hour. Try to make the update atomic.
  • Now that the browser request comes in, just return what is in the cache.
+2
source

All Articles