Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a global variable defined inside a Sinatra route shared between requests?

Say I've got:

get '/' do
 $random = Random.rand()
 response.body = $random
end

If I have thousands of requests per second coming to /, will the $random be shared and 'leak' outside the context or will it act like a 'local' variable to the get block?

I imagine if it was defined outside of the context of get '/' do it would indeed be shared but I wonder if there's a mechanic to $ in ruby that I'm not aware of.

like image 856
dsp_099 Avatar asked Jan 17 '13 21:01

dsp_099


1 Answers

This part of the Sinatra README about scope is always helpful to read but if you only need the variable to persist for the request then I think there are 3 main ways I'd suggest going about this, and really the key is a filter

A before block

before do
  @my_log = []
end

get "/" do
  @my_log << "hello"
  @my_log << "world"
  @my_log.inspect
end

get "/something-else" do
  @my_log << "is visible here too"
end

# => output is ["hello", "world"]

@my_log will go out of scope at the end of the request and be re-initialised at the beginning of the next one. It will be accessible by any route, so if for example you used pass to pass it on to another route that would be the only time the other blocks could see what had been set by the prior route block.

Using the settings helper

set :mylog, []

Then same as above, just replace @my_log with settings.my_log. Without the before block reinitialising it then the contents of @my_log would be persisted across requests.

Using the settings helper with something like Redis

# I always do this within a config block as then it's only initialised once
config do
  uri = URI.parse(ENV["URL_TO_REDIS"])
  set :redis, Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
end

Now the redis instance is available via settings.redis. No need to worry about variable scope (I'd use locals with it), just push straight to Redis. You get the best of both worlds then, but if you want you could do:

before do
  @my_log = []
end

get "/" do
  @my_log << "hello"
  @my_log << "world"
  "Hello, World"
end

after do
  settings.redis.set "some_key", @my_log
  settings.redis.expire "some_key", 600 # or whatever
end
like image 144
ian Avatar answered Oct 26 '22 17:10

ian