可以使用Ohm for Ruby的整个对象的内容到期?

时间:2012-04-04 18:00:52

标签: ruby-on-rails ruby redis ohm

一旦我的特定事件发生,我希望能够在Ruby on Rails应用程序中使基于欧姆的对象的全部内容失效。是否有可能将Redis + expire与当前相关联?使用Ohm时,对象有多个与之关联的键,包括索引等。我想确保所有内容都得到正确清理 - 这就是为什么我想知道是否有正式支持的方法。

3 个答案:

答案 0 :(得分:2)

不幸的是,没有。已经有过几次尝试来解决这个难题,但是我看过的每一个都留下了Ohm数据集中的工件。它们都没有使用唯一属性,据我所知,所有这些都使Ohm数据处于不一致状态。

一些例子:

例如,当欧姆模型保存时,Redis哈希中会添加几个字段,并且还会将成员添加到Redis集中。虽然您可以在整个散列或集合上设置过期,但您不能使Redis散列的单个字段或集合中的单个成员过期。整个散列或集合都会过期。

这是主要问题:如果这些集合和哈希值过期,您将丢失模型上的整个索引,或者您的唯一属性的完整记录。因此,使用任何Ohm expire mixins时的一个常见问题是,即使主数据键到期,对find的调用仍将从索引返回记录,但是使用nil哈希值。如果您在模型中指定了唯一属性,那么即使数据本身已过期,您也不能再使用过期值调用该模型上的create而不引发异常。

Redis中没有到期回调,因此当特定键到期时,无法触发删除哈希字段或设置成员。有几个人要求允许哈希字段或设置成员在Redis问题列表上有TTL,但是他们已经(非常合理地)关闭了答案such as this

  

嗨,这不会由原始设计实现:

     

键中没有嵌套类型。单个字段中没有复杂的特征   聚合数据类型。推理要复杂得多,而且很多   个人感受,偏好和感性偏见所以没有   客观的方式我可以告诉你这是更好的;)

     

截止。感谢您的报道。

例如,以下是来自Ohm源代码(ohm.rb, 651-699)的一些注释:

  # The base class for all your models. In order to better understand
  # it, here is a semi-realtime explanation of the details involved
  # when creating a User instance.
  #
  # Example:
  #
  #   class User < Ohm::Model
  #     attribute :name
  #     index :name
  #
  #     attribute :email
  #     unique :email
  #
  #     counter :points
  #
  #     set :posts, :Post
  #   end
  #
  #   u = User.create(:name => "John", :email => "foo@bar.com")
  #   u.incr :points
  #   u.posts.add(Post.create)
  #
  # When you execute `User.create(...)`, you run the following Redis
  # commands:
  #
  #   # Generate an ID
  #   INCR User:id
  #
  #   # Add the newly generated ID, (let's assume the ID is 1).
  #   SADD User:all 1
  #
  #   # Store the unique index
  #   HSET User:uniques:email foo@bar.com 1
  #
  #   # Store the name index
  #   SADD User:indices:name:John 1
  #
  #   # Store the HASH
  #   HMSET User:1 name John email foo@bar.com
  #
  # Next we increment points:
  #
  #   HINCR User:1:counters points 1
  #
  # And then we add a Post to the `posts` set.
  # (For brevity, let's assume the Post created has an ID of 1).
  #
  #   SADD User:1:posts 1
  #

但是人们通常试图使欧姆数据过期的方式是这样的更简单(没有操纵独特的或模型范围的索引):

  Ohm.redis.expire(object.key, @expire)
  Ohm.redis.expire("#{object.key}:_indices", @expire)

总之,在Redis中对数据到期进行细粒度控制的最佳方法是使用低级接口(如redis-rb)设计自己的存储方法。

答案 1 :(得分:1)

使用Redis过期而不是过期,一种更可靠的方法来终止Ohm对象是直接检查和删除对象,例如通过具有单独的到期线程。这可以检查模型对象,检测已过期的对象,并通过Ohm请求删除。

Ohm使用Lua script以原子方式执行删除,这会正确清除与该对象关联的任何键,并从其他Ohm结构中删除对该对象的引用。使用欧姆删除是清除过期的最佳选择。

通过使用这样的设计,您可能需要权衡性能以确保可靠性:您的程序基本上将跨所有已知对象执行垃圾收集,这可能涉及大量内存访问和/或Redis查询。

以下是清理线程如何工作的示例:

def start_expiry_thread expiry_cycle

  Thread.new {

    while (true) do

      MyOhmModel.all.each do |object|
        object.delete if object.expired
      end

      sleep expiry_cycle

    end

  }

end

在Ohm模型类中,可以通过以下几行实现过期函数(通过继承或mixin),并支持Ohm :: Timestamps模块:

@max_life = 3600

def expired            
    (time_since_update > @max_life)
end

def time_since_update
    updated_secs = self.updated_at.to_i
    (Time.now.to_i - updated_secs)
end

注意:

  • 引入线程时要小心 - 使用锁定来防止 通过两个线程同时访问同一个对象,或简单地 避免共享对象并让你的到期线程直接进入 Redis的。

  • 如果您的申请流程定期重启, 另一种方法是在启动过程中进行清理, 在任何其他工作线程启动之前。

  • 确保你的另一个 应用程序代码优雅地处理到期 - 底层的Redis 对象将消失,这意味着任何等效的对象 应用程序代码无效。

  • 以上是生产系统中代码的简化版本,因此在简化过程中可能会出现错误。

  • 更一般地说:请检查你真的需要欧姆。如果您正在考虑在键值存储上添加相关层的数量,那么您应该考虑系统的技术设计。

答案 2 :(得分:0)

我为Ohm开发了一颗宝石来照顾它。

看看:ohm-expire