I have built a pretty simple REST service in Sinatra, on Rack. It's backed by 3 Tokyo Cabinet/Table datastores, which have connections that need to be opened and closed. I have two model classes written in straight Ruby that currently simply connect, get or put what they need, and then disconnect. Obviously, this isn't going to work long-term.
I also have some Rack middleware like Warden that rely on these model classes.
What's the best way to manage opening and closing the connections? Rack doesn't provide startup/shutdown hooks as I'm aware. I thought about inserting a piece of middleware that provides reference to the TC/TT object in env, but then I'd have to pipe that through Sinatra to the models, which doesn't seem efficient either; and that would only get be a per-request connection to TC. I'd imagine that per-server-instance-lifecycle would be a more appropriate lifespan.
Thanks!
Have you considered using Sinatra's configure blocks to set up your connections?
configure do
Connection.initialize_for_development
end
configure :production do
Connection.initialize_for_production
end
That's a pretty common idiom while using things like DataMapper with Sinatra
Check out the "Configuration" section at http://www.sinatrarb.com/intro
If you have other Rack middleware that depend on these connections (by way of a dependence on your model classes), then I wouldn't put the connection logic in Sinatra -- what happens if you rip out Sinatra and put in another endpoint?
Since you want connection-per-application rather than connection-per-request, you could easily write a middleware that initialized and cleaned up connections (sort of the Guard Idiom as applied to Rack) and install it ahead of any other middleware that need the connections.
class TokyoCabinetConnectionManagerMiddleware
class <<self
attr_accessor :connection
end
def initialize(app)
#app = app
end
def call(env)
open_connection_if_necessary!
#app.call(env)
end
protected
def open_connection_if_necessary!
self.class.connection ||= begin
... initialize the connection ..
add_finalizer_hook!
end
end
def add_finalizer_hook!
at_exit do
begin
TokyoCabinetConnectionManagerMiddleware.connection.close!
rescue WhateverTokyoCabinetCanRaise => e
puts "Error closing Tokyo Cabinet connection. You might have to clean up manually."
end
end
end
end
If you later decide you want connection-per-thread or connection-per-request, you can change this middleware to put the connection in the env Hash, but you'll need to change your models as well. Perhaps this middleware could set a connection variable in each model class instead of storing it internally? In that case, you might want to do more checking about the state of the connection in the at_exit hook because another thread/request might have closed it.
Related
I'm stumped I've tried everything I can think of to work around this and I got nothing.
When does Sinatra's request object start existing and where does it actually exist and how can I get to it from anywhere? i.e. another class that inherits from a class that inherits from a class that inherits from Sinatra::Base for example.
I've managed to get an idea of where it exists from this question but I just can't seem get any further.
Things I've tried:
def self.request
self.superclass.superclass.superclass.request
end
Various ways of changing the code execution context using `instance_eval or using:
def self.method_added method_name
a = self.new.method(method_name)
def self.define_method method_name do
a.call
end
end
and anything else I can think of but no matter what I do request is always nil, so I ask again, when and where does the request object come into existence during a request?
EDIT:
No offence but how is it hard to tell what I'm asking?
Here's the question, it's the in the title:
When and where does Sinatra's request object exist?
Sinatra has a request object, when does the object start to exist? (as in when is it not nil during the execution of code?)
When it does exist, where does it exist, within Sinatra::Base an instance of Sinatra::Base or within `Wrapper or some where else?
EDIT:
Here's what I'm doing:
in this example:
r[:action] is 'get'
r[:url] is '/'
method is get_root
instance is a variable storing self.new so I can access any instance methods.
def method_added method
return if Delegation::SIN_DSL[:basic].include?(method)
r,p = get_r_data method
m = self.instance.method(method)
self.send r[:action], r[:url].first, (#options || {}) do
(m.arity < 1 ) ? m.call : m.call(*p)
end
#options = nil
end
A sinatra app is a rack app. If you have
class MyApp < Sinatra::Base
end
then where the MyApp class gets instantiated depends on how you start up a webserver that runs it; generally speaking the rack handler (which may be of different types depending on the http server you're using) will store an instance of the sinatra app. When a rack request comes in, the server or another rack app will call the app instance with the rack env hash. Sinatra::Base#call will then do dup.call!(env), meaning that a shallow copy of the existing instance is made and then call! is invoked on the copy. The body of call! is where the request object is initialized:
def call!(env) # :nodoc:
#env = env
#request = Request.new(env)
and it's this duped app's request accessor for this instance variable that you're typically invoking when you refer to request in a route handler.
Not sure if that helps you, but it should at least answer the question.
WARNING: Answer valid for sinatra v1.4.5, but you should not expect it to remain valid. These implementation details are not part of the public sinatra API and are not documented for a reason -- you're not intended to mess with it, and doing so will quite possibly break your app if you upgrade sinatra versions. I don't recommend writing code that depends on these details.
Is there a way to have objects on a Rails app that conserve their state between HTTP transactions?
For example, can I initialize a Net::LDAP connection somewhere and use it to retrieve data only restarting it on lost connection?
You can use class variables.
class Connection
def initialize
##connection ||= # Start connectio
end
end
I'm little new to Ruby, but I have the following coded using Grape API in Ruby. I have #data = YAML.load() called every time it hits GET /api/v1/foo, is there a way in Grape to only load it once and use it? This way is more optimized and not calling YAML.load() at every time. Should I override the initialize method and put a super() for this operation?
Thanks,
require 'grape'
require 'json'
require "yaml"
module MyProject
CONFIG_FILE = "./config.yml"
class Api < Grape::API
rescue_from :all
prefix 'api'
version 'v1'
format :json
resources :foo do
get do
#data = YAML.load(File.open(MyProject::CONFIG_FILE))
end
end
end
end
The short answer is that Grape doesn't work quite how you think, and attribute variables of the MyProject::Api are not the way forward for your new web service. However, it is an interesting question, and worth exploring why this is so.
If you add a puts self.inspect inside the resources :foo block, and run using rackup, when you call the route you should see that self is in fact a Grape::Endpoint object. Also, no matter what you try to do with instance variables, they will always start in the same state for each request. That is because Grape turns your route definitions into prepared Grape::Endpoint objects, with a lot of the definition data and setup put into a quickly-accessible form (so that it is not figured out on each request). Eventually, on each request, the matching Grape::Endpoint object including your block (and other details you defined for the route) is duplicated before being called, meaning that state is not maintained between requests.
This may seem complicated, but most frameworks covering web service requests will do something similar. Generally you don't want request-handling state to persist between requests. Frameworks with larger scope - e.g. Rails - have places to put more persistent data planned out for you. Grape does not have this defined, which has its pros and cons. One obvious plus point is that you are more free to use whatever other data persistence approach that you wish to.
23tux's answer will sort you out immediately for loading config. Although I'm not entirely sure how ##data becomes accessible to the endpoint block (it may even be creating a closure around the variable).
Longer term, you should look to moving config management out of your MyProject::Api class, and including it as a module via Grape's helpers method (I'm happy to provide an example if you are interested).
Edit: Example based on your current code, but moving config management to a separate module:
require 'grape'
require 'json'
require "yaml"
module MyProject
module Config
CONFIG_FILE = "./config.yml"
##data = nil
def config
##data ||= YAML.load( File.open( CONFIG_FILE ) )
end
end
class Api < Grape::API
rescue_from :all
prefix 'api'
version 'v1'
format :json
helpers MyProject::Config
resources :foo do
get do
config
end
end
end
end
This is one step further, structurally, than 23tux's answer, but is still not completely separating concerns of storage (and caching etc) versus api access. As you progress towards a more sophisticated web service, you will want to keep the Grape route definitions simple, with only a small amount of logic that manages or manipulates the data - well, at least as seen directly in the blocks.
One way to link between your Grape definitions, and other gems that might manage config, logging, authentication and other services, is via Grape's helpers method. Grape also has some built-in helper methods for common tasks.
The main exception to using helpers MyModule to add shared functions into Grape is when you want to manage displaying data objects (aka "models") from your core application. For that you have a few choices, but the grape-entity gem and the present method is not a bad place to start.
If the #data is the same for the whole api, and doesn't change at any time, just use a class variable
require 'grape'
require 'json'
require "yaml"
module MyProject
CONFIG_FILE = "./config.yml"
class Api < Grape::API
##data = YAML.load(File.open(MyProject::CONFIG_FILE))
rescue_from :all
prefix 'api'
version 'v1'
format :json
resources :foo do
get do
puts ##data
end
end
end
end
Not tested, but with this way, you ensure that the data is only loaded once, when your Api class is loaded
I am currently building a Thor executable that supports several different tasks. Some tasks inoke other tasks. For example
Auth
authenticates the local user
Create
Invoke Auth
Does something
Invoke Configure
Configure:
Invoke Auth
Does something
The nice thing about thor is that I can now call all of the three tasks separately, but be sure that authenticate for example is only called once through invoke.
But what is now the best way to share Data between those tasks. For example when Authenticating I want to set the User-ID of the current user. Thus when I want to request Data from our webservice I can take the user id from anywhere in my code the same way.
Right now I am implementing this through Modules, but I am not really sure if this is the best way to do it.
Using Singleton would be another way, but somehow this seems like a little bit too much for this purpose.
Maybe you guys have experience with a better way to do this, or maybe using modules is the best way to store the information anyway.
I would have done something like this:
module PRJ
class << self
attr_accessor :api_key, :account_name, :api_version, :api_url, ......
def configure
yield self
end
end
end
require "#{directory_of_all_other_classes}"
require 'thor'
class CLI < Thor
include Thor::Actions
def login
...
PRJ.api_key = response[:api_key]
end
As you want to invoke Auth in every cases, so I think it should be in main CLI file.
Regarding storing and using data it would be better to use attributes instead of constant. I may not be right about this but I prefer using class attributes.
Now you can access and change PRJ.api_key from anywhere (require PRJ module in every file)
P.S. The structure of code snippet might not be accurate, I just wanted to share some basic skeleton. Do something like above for remaining classes.
If you just need to store simple data structures I would go for common class variables
class Test < Thor
##my_shared_var = nil
desc 'my_first_task','sdfasdf'
def my_first_task
##my_shared_var = 'foo'
end
desc 'my_second_task','sdfasdf'
def my_second_task
invoke :my_first_task
puts ##my_shared_var
end
end
I have built a pretty simple REST service in Sinatra, on Rack. It's backed by 3 Tokyo Cabinet/Table datastores, which have connections that need to be opened and closed. I have two model classes written in straight Ruby that currently simply connect, get or put what they need, and then disconnect. Obviously, this isn't going to work long-term.
I also have some Rack middleware like Warden that rely on these model classes.
What's the best way to manage opening and closing the connections? Rack doesn't provide startup/shutdown hooks as I'm aware. I thought about inserting a piece of middleware that provides reference to the TC/TT object in env, but then I'd have to pipe that through Sinatra to the models, which doesn't seem efficient either; and that would only get be a per-request connection to TC. I'd imagine that per-server-instance-lifecycle would be a more appropriate lifespan.
Thanks!
Have you considered using Sinatra's configure blocks to set up your connections?
configure do
Connection.initialize_for_development
end
configure :production do
Connection.initialize_for_production
end
That's a pretty common idiom while using things like DataMapper with Sinatra
Check out the "Configuration" section at http://www.sinatrarb.com/intro
If you have other Rack middleware that depend on these connections (by way of a dependence on your model classes), then I wouldn't put the connection logic in Sinatra -- what happens if you rip out Sinatra and put in another endpoint?
Since you want connection-per-application rather than connection-per-request, you could easily write a middleware that initialized and cleaned up connections (sort of the Guard Idiom as applied to Rack) and install it ahead of any other middleware that need the connections.
class TokyoCabinetConnectionManagerMiddleware
class <<self
attr_accessor :connection
end
def initialize(app)
#app = app
end
def call(env)
open_connection_if_necessary!
#app.call(env)
end
protected
def open_connection_if_necessary!
self.class.connection ||= begin
... initialize the connection ..
add_finalizer_hook!
end
end
def add_finalizer_hook!
at_exit do
begin
TokyoCabinetConnectionManagerMiddleware.connection.close!
rescue WhateverTokyoCabinetCanRaise => e
puts "Error closing Tokyo Cabinet connection. You might have to clean up manually."
end
end
end
end
If you later decide you want connection-per-thread or connection-per-request, you can change this middleware to put the connection in the env Hash, but you'll need to change your models as well. Perhaps this middleware could set a connection variable in each model class instead of storing it internally? In that case, you might want to do more checking about the state of the connection in the at_exit hook because another thread/request might have closed it.