1

我正在尝试将 Rails 请求缓存到需要 proc 的外部服务。

为了让我能够区分 2 个请求,proc 是 Rails 缓存键的一部分很重要。

但是,具有相同 proc 和 proc 代码中的值的多个请求每次仍会评估为不同的 proc 对象。

例如:

#<Proc:0x007ff6f675dd08@/Users/app/development/work/runner.rb:10>
#<Proc:0x007ff6ffb50790@/Users/app/development/work/runner.rb:10>

因此,即使对于相同的请求,我也会遇到缓存未命中。

如果 proc 在代码和变量值方面相同,我如何使用缓存键中的块/proc 计算结果相同。

服务调用类似于

def some_method    
  call_service do 
    a= 3;
    b=6
  end
end

 def call_service(block)
       Rails.cache.fetch(Date.today, block) {
         external_service(&block)
       }
  end

 I want to be able to compare blocks :
eg 
{a=3, a*a} == {a=3, a*a}  => True
{a=3, a*a} == {a=4, a*a}  => false
{a=3, a*a} == {a=4, a*a*a} => False

我尝试使用,

block.source
RubyVM::InstructionSequence.of(block).disasm

但是它们都没有捕获块的状态,即变量的值(a = 3等)

在 rails 中实现这种缓存的最佳方法是什么?

PS:

使用 Rails4 和 reddis 作为缓存

4

2 回答 2

0

每次你定义一个内联块时,do ... end你都会得到一个不同的Proc 对象。您必须竭尽全力确保您通过完全相同的 Proc 发送:

def some_method    
  @my_call ||= lambda {
    a = 3
    b = 6
  }

  call_service(&@my_call)
end

这可能从一开始就是一个坏主意。你最好做的是传入一个缓存键:

call_service("3/6") do
  # ...
end

然后你缓存这个一致的键,而不是任意的 Proc。

于 2013-10-25T18:43:19.540 回答
0

您可能会通过这种方式获得一些里程。此函数返回一个简单的 Proc 对象。该对象将具有一个源位置和一个绑定,该绑定包含构建 Proc 时参数 a、b 和 c 的状态。

def build_proc(a, b, c)
  Proc.new { puts "I was built with params #{a} #{b} #{c}!" }
end

所以我们可以构建我们的 Proc 对象——

2.0.0-p195 :121 > p1 = build_proc(1, 2, 3)
=> #<Proc:0x98849e8@(irb):118> 
2.0.0-p195 :122 > p2 = build_proc(2, 4, 6)
=> #<Proc:0x985e57c@(irb):118> 

要获取参数的状态,您可以binding.eval('argument')针对 Proc 对象调用。这会在该 Proc 绑定的上下文中运行代码。所以你可以说——

p1.binding.eval('[a, b, c]') == p2.binding.eval('[a, b, c]')

2.0.0-p195 :127 > p1.binding.eval('[a, b, c]') == p2.binding.eval('[a, b, c]')
 => false 
2.0.0-p195 :128 > p2 = build_proc(1, 2, 3)
 => #<Proc:0x97ae4b0@(irb):118> 
2.0.0-p195 :129 > p1.binding.eval('[a, b, c]') == p2.binding.eval('[a, b, c]')
 => true 

显然你可以比较源位置——

p1.source_location == p2.source_location && 
p1.binding.eval('[a, b, c]') == p2.binding.eval('[a, b, c]')

您需要一种以通用方式从绑定中提取参数的方法,并且您希望组合它们的哈希而不是构建一个数组进行比较(例如'a.hash ^ b.hash ^ c.hash')。

不过这确实感觉很可怕!至少,覆盖:==Procs 可能是个坏主意。

于 2013-10-25T19:07:36.550 回答