简体   繁体   English

Ruby Rack:启动和拆卸操作(东京内阁连接)

[英]Ruby Rack: startup and teardown operations (Tokyo Cabinet connection)

I have built a pretty simple REST service in Sinatra, on Rack. 我在Rack的Sinatra中建立了一个非常简单的REST服务。 It's backed by 3 Tokyo Cabinet/Table datastores, which have connections that need to be opened and closed. 它由3个Tokyo Cabinet / Table数据存储提供支持,这些数据存储具有需要打开和关闭的连接。 I have two model classes written in straight Ruby that currently simply connect, get or put what they need, and then disconnect. 我有两个直接用Ruby编写的模型类,它们当前仅连接,获取或放置所需的对象,然后断开连接。 Obviously, this isn't going to work long-term. 显然,这不会长期有效。

I also have some Rack middleware like Warden that rely on these model classes. 我也有一些像Warden这样的Rack中间件,它们依赖于这些模型类。

What's the best way to manage opening and closing the connections? 管理打开和关闭连接的最佳方法是什么? Rack doesn't provide startup/shutdown hooks as I'm aware. 据我所知,Rack不提供启动/关闭挂钩。 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; 我曾考虑过要在env中插入一个提供对TC / TT对象的引用的中间件,但随后我不得不通过Sinatra将其通过管道传递给模型,这似乎也不高效; and that would only get be a per-request connection to TC. 而这只能是针对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? 您是否考虑过使用Sinatra的configure模块来建立连接?

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 这是在Sinatra中使用DataMapper之类的习惯用法

Check out the "Configuration" section at http://www.sinatrarb.com/intro 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? 如果您有其他依赖于这些连接的Rack中间件(通过对模型类的依赖),那么我就不会将连接逻辑放在Sinatra中-如果您将Sinatra撕裂并放入另一个端点会怎样?

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. 由于您希望按应用程序连接而不是按请求连接,因此您可以轻松编写一个初始化和清理连接的中间件(类似于应用于Rack的Guard Idiom),并在需要该连接的任何其他中间件之前安装它连接。

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. 如果以后决定要按线程连接还是按请求连接,则可以更改此中间件以将连接放入env Hash ,但是您还需要更改模型。 Perhaps this middleware could set a connection variable in each model class instead of storing it internally? 也许这个中间件可以在每个模型类中设置一个connection变量,而不是在内部存储它? 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. 在这种情况下,您可能希望对at_exit挂钩中的连接状态进行更多检查,因为另一个线程/请求可能已将其关闭。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM