我在 Sinatra 的 Rack 上构建了一个非常简单的 REST 服务。它由 3 个 Tokyo Cabinet /表数据存储提供支持,这些数据存储具有需要打开和关闭的连接。我有两个用直接 Ruby 编写的模型类,它们目前只是连接、获取或放置他们需要的东西,然后断开连接。显然,这不会长期奏效。
我还有一些 Rack 中间件,比如 Warden,它们依赖于这些模型类。
管理打开和关闭连接的最佳方法是什么?据我所知,Rack 不提供启动/关闭 Hook 。我想过在 env 中插入一个提供对 TC/TT 对象的引用的中间件,但随后我必须通过 Sinatra 将其通过管道传输到模型,这似乎也不高效;并且这只会成为到 TC 的每个请求连接。我想每个服务器实例的生命周期将是一个更合适的生命周期。
谢谢!
最佳答案
如果您有其他依赖于这些连接的 Rack 中间件(通过依赖于您的模型类的方式),那么我不会将连接逻辑放在 Sinatra 中——如果您撕掉 Sinatra 并放入另一个端点会发生什么?
由于您想要每个应用程序的连接而不是每个请求的连接,您可以轻松编写一个初始化和清理连接的中间件(类似于应用于 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
如果您稍后决定需要每线程连接或每请求连接,您可以更改此中间件以将连接放在
env Hash
中,但您也需要更改模型。也许这个中间件可以在每个模型类中设置一个 connection
变量而不是在内部存储它?在这种情况下,您可能需要更多地检查 at_exit
Hook 中的连接状态,因为另一个线程/请求可能已关闭它。关于 ruby Rack : startup and teardown operations (Tokyo Cabinet connection),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2582822/