tjrburgess
tjrburgess

Reputation: 787

cache variable in Sinatra

I have a set of of ~60 sorted sets each containing a ~200 members which I am trying to process. Previously I built a Redis (Lua) serverside script but the big(O) time values of the request bog down under load.

I am now trying to offload the processing to Ruby/Sinatra and refreshing the results on every request proving to be inefficient. Given the code below, is there an way to cache the "scores" results in Sinatra so I don't have to pull from Redis on every request?

global = redis.smembers("id_list")

i=0
scores = redis.pipelined do
  global.each do |key|
    redis.zrange("user:#{global[i]}",0,100,:with_scores => true)
    i+=1
  end
end

Upvotes: 1

Views: 783

Answers (1)

mattwise
mattwise

Reputation: 1506

Sinatra has a global scope where objects will persist between requests. If you have a scorekeeper class defined which maintains an instance variable for your score, then you can have a lookup method for the score which holds the value. For example:

class Scorekeeper
  def initialize
    @scores = nil
  end

  def scores
    @scores ||= get_scores
  end

  def get_scores
    global = redis.smembers("id_list")
    i=0
    scores = redis.pipelined do
      global.each do |key|
        redis.zrange("user:#{global[i]}",0,100,:with_scores => true)
        i+=1
      end
    end
    scores
  end
end

Now your Sinatra app just needs to instantiate a scorekeeper outside of any resource declaration:

require 'sinatra'
keeper = Scorekeeper.new

get '/scores' do
  keeper.scores
end

This way on the first request, the scores property will get populated, on all further requests, it will use the cached value.

Upvotes: 3

Related Questions