2017-01-24 33 views
0

我发送用户更新到外部服务,定期,一个Sidekiq工人中运行的包装。每个用户都有自己的Sidekiq作业。 Sidekiq设置为使用20个线程。这是一个Rails 5.0.1应用程序,MRI Ruby 2.3.0。 Webserver是Passenger 5社区。Ruby对象突变

如果我在简化,代码如下所示:

class ProviderUserUpdateJob < ApplicationJob 
    queue_as :default 

    def perform(user_id) 
    user = User.find(user_id) 
    Provider::User.new(user).push_update 
    end 
end 


class Provider::User 

    def initialize(user) 
    @user = user 
    end 

    def push_update 
    SomeApiWrapper.call(
     user_id: @user.id, 
     status: @user.status 
    ) 
    end 

    .... 
end 

现在,最大的问题,我只对生产,我终于逮住了通过查看日志可以这样概括:

class Provider::User 

    def initialize(user) 
    @user = user 
    end 

    def push_update 
    SomeApiWrapper.call(
     user_id: @user.id, # Some user 
     status: @user.status # NOT THE SAME USER !!! (and I have no idea where he is coming from) 
    ) 
    end 

    .... 
end 

2个问题:

  1. 它是如何这甚至可能吗?它是否来自Provider :: User本质上是一个全局可访问的对象,因此,从线程到线程,所有东西都会混杂在一个变异的汤中?

  2. 如果我只用“功能性”的风格,没有任何实例,传递参数和输出从静态方法静态方法,它可以解决我的问题,还是我完全错了吗?我怎样才能解决这个问题?

最终,有没有什么办法可以真正对战测试这种代码,所以我可以肯定不会混合用户数据?

+0

_“如果我在简化,代码看起来像这样” _ - 和它的bug仍然与简化的代码发生的呢? – Stefan

+0

哈哈,好的。我的错。但尽管它被简化了,但问题的确切位置和行为仍与原始代码保持一致:“@user”在生产中随机地指向其他内容,从一行到另一行。连续两次调用“@user”变量之间绝对没有任何区别,这一点在这里并没有简化。 – gbarillot

+0

对'id'或'status'的调用是否会产生副作用,使接收方发生变异?如果不是,那么'SomeApiWrapper.call'线程安全吗? – Stefan

回答

0

好吧......原来,这是一个伪数据的问题。我花了2个小时试图找出复杂的解释,但答案只是在我的数据库中。干得好: -/