当推入序列化字段时,sidekiq 的奇怪行为在邮件程序上返回了 jid
Odd behaviour with sidekiq returned jid on a mailer when pushing into a serialised field
当我试图将 worker 返回的 jid 推送到模型上的序列化字段时,我遇到了一些奇怪的行为。此代码的最佳解释:
class Foo < ActiveRecord::Base
serialize :jids, Array
def do_job
test_jids = []
jids << "s"
test_jids << "s"
Rails.logger.info("s has been pushed")
Rails.logger.info(jids)
Rails.logger.info(test_jids)
jids << BarWorker.perform_in(10.minutes, self.id)
test_jids << BarWorker.perform_in(10.minutes, self.id)
Rails.logger.info("normal worker has been pushed")
Rails.logger.info(jids)
Rails.logger.info(test_jids)
jids << FooMailer.delay_for(10.minutes).confirm_foo(self)
test_jids << FooMailer.delay_for(10.minutes).confirm_foo(self)
Rails.logger.info("mailer worker id pushed")
Rails.logger.info(jids)
Rails.logger.info(test_jids)
jids
end
end
预期日志记录:
s has been pushed
["s"]
["s"]
normal worker has been pushed
["s", "6d25faf98b6448a43e1d3bb5"]
["s", "7144ceab11ece07ae352ffb9"]
mailer worker id pushed
["s", "6d25faf98b6448a43e1d3bb5", "54c4634bfc11ec1adad926da"]
["s", "7144ceab11ece07ae352ffb9", "3d0bb94e0411a04ab0339f68"]
实际记录。
s has been pushed
["s"]
["s"]
normal worker has been pushed
["s", "243675806204134e6f05abaa"]
["s", "1444f558d7582df1000c6f4b"]
mailer worker id pushed
["s", "243675806204134e6f05abaa"]
["s", "1444f558d7582df1000c6f4b", "c0878213a8ea5f783c30e666"]
邮件程序的作业 ID 尚未推送到 foo 上的 jids 属性中。
在混乱中,我有点 hacky 并在 Foo
上写了这个方法
def do_job_with_assignment
test_jids = []
jids << "s"
test_jids << "s"
Rails.logger.info("s has been pushed")
Rails.logger.info(jids)
Rails.logger.info(test_jids)
bar_worker_jid = BarWorker.perform_in(10.minutes, self.id)
jids << bar_worker_jid
test_bar_worker_jid = BarWorker.perform_in(10.minutes, self.id)
test_jids << test_bar_worker_jid
Rails.logger.info("normal worker has been pushed")
Rails.logger.info(jids)
Rails.logger.info(test_jids)
foo_mailer_jid = FooMailer.delay_for(10.minutes).confirm_foo(self)
jids << foo_mailer_jid
test_foo_mailer_jid = FooMailer.delay_for(10.minutes).confirm_foo(self)
test_jids << test_foo_mailer_jid
Rails.logger.info("mailer worker id pushed")
Rails.logger.info(jids)
Rails.logger.info(test_jids)
jids
end
现在 确实 产生了预期的日志记录。
除了显而易见的,两者之间还有什么区别?
编辑:
没有人领取赏金,我想更进一步,但我不确定问题出在哪里。有人建议好的起点吗?
编辑:类
> Foo.new.jids.class
=> Array
> BarWorker.perform_in(10.minutes, 1).class
=> String
> FooMailer.delay_for(10.minutes).confirm_foo(self).class
=> String
编辑:
这是我的分析...
jids
是 Foo
class 成员...以及 sidekiq 在后台工作的方式(使用 celluloid 功能不允许竞争条件并避免死锁和一堆我不知道的其他功能)..让它在后台线程中完成大部分工作...
如果我的分析是正确的...那么日志记录可能如下所示
foo = Foo.new
foo.do_job
# logs show the following
["s", "243675806204134e6f05abaa"]
["s", "1444f558d7582df1000c6f4b", "c0878213a8ea5f783c30e666"]
foo.jids
=>["s", "243675806204134e6f05abaa"]
foo.reload
foo.jids
=>["s", "243675806204134e6f05abaa", "I'm new here"]
虽然 test_jids
是一个本地数组,可能会在方法结束之前使用...这就是它立即返回的原因..(这就是为什么您的解决方法有效的原因:D 有事可做线程的工作方式)...
如有错误请指正...
如果我没记错的话...您需要更多详细信息...您必须深入了解 sidkiq 和 celluloid 如何管理它们的线程
也看看下面的
我认为这是因为 Rails 缓存了除序列化字段之外的所有列类型的属性。考虑到这一点,当您在 getter 上为 jids
调用 <<
方法时,Rails 会获取该字段的属性,但是当您将 self
传递给邮件程序在 Sidekiq 中序列化时再次调用 getter,并覆盖属性实例,因此返回值不会添加到正确的 jids 实例中。
我不确定我是否完全理解为什么会发生这种情况,所以一些具体的实施细节可能不太准确!
这可以 fixed/made 通过以下方式之一使用此版本的 Rails (4.1.5):
缓存 jids
属性:
class Foo < ActiveRecord::Base
serialize :jids, Array
cache_attributes :jids
使用 jids
setter:
jids = self.jids << FooMailer.delay_for(10.minutes).confirm_foo(self)
将 id
或副本传递到邮件程序中:
jids << FooMailer.delay_for(10.minutes).confirm_foo(id)
# or
jids << FooMailer.delay_for(10.minutes).confirm_foo(self.dup)
这在 Rails 4.2 中已修复,当此代码被重写时,我可以找到一个 PR:https://github.com/rails/rails/pull/15429
当我试图将 worker 返回的 jid 推送到模型上的序列化字段时,我遇到了一些奇怪的行为。此代码的最佳解释:
class Foo < ActiveRecord::Base
serialize :jids, Array
def do_job
test_jids = []
jids << "s"
test_jids << "s"
Rails.logger.info("s has been pushed")
Rails.logger.info(jids)
Rails.logger.info(test_jids)
jids << BarWorker.perform_in(10.minutes, self.id)
test_jids << BarWorker.perform_in(10.minutes, self.id)
Rails.logger.info("normal worker has been pushed")
Rails.logger.info(jids)
Rails.logger.info(test_jids)
jids << FooMailer.delay_for(10.minutes).confirm_foo(self)
test_jids << FooMailer.delay_for(10.minutes).confirm_foo(self)
Rails.logger.info("mailer worker id pushed")
Rails.logger.info(jids)
Rails.logger.info(test_jids)
jids
end
end
预期日志记录:
s has been pushed
["s"]
["s"]
normal worker has been pushed
["s", "6d25faf98b6448a43e1d3bb5"]
["s", "7144ceab11ece07ae352ffb9"]
mailer worker id pushed
["s", "6d25faf98b6448a43e1d3bb5", "54c4634bfc11ec1adad926da"]
["s", "7144ceab11ece07ae352ffb9", "3d0bb94e0411a04ab0339f68"]
实际记录。
s has been pushed
["s"]
["s"]
normal worker has been pushed
["s", "243675806204134e6f05abaa"]
["s", "1444f558d7582df1000c6f4b"]
mailer worker id pushed
["s", "243675806204134e6f05abaa"]
["s", "1444f558d7582df1000c6f4b", "c0878213a8ea5f783c30e666"]
邮件程序的作业 ID 尚未推送到 foo 上的 jids 属性中。
在混乱中,我有点 hacky 并在 Foo
def do_job_with_assignment
test_jids = []
jids << "s"
test_jids << "s"
Rails.logger.info("s has been pushed")
Rails.logger.info(jids)
Rails.logger.info(test_jids)
bar_worker_jid = BarWorker.perform_in(10.minutes, self.id)
jids << bar_worker_jid
test_bar_worker_jid = BarWorker.perform_in(10.minutes, self.id)
test_jids << test_bar_worker_jid
Rails.logger.info("normal worker has been pushed")
Rails.logger.info(jids)
Rails.logger.info(test_jids)
foo_mailer_jid = FooMailer.delay_for(10.minutes).confirm_foo(self)
jids << foo_mailer_jid
test_foo_mailer_jid = FooMailer.delay_for(10.minutes).confirm_foo(self)
test_jids << test_foo_mailer_jid
Rails.logger.info("mailer worker id pushed")
Rails.logger.info(jids)
Rails.logger.info(test_jids)
jids
end
现在 确实 产生了预期的日志记录。
除了显而易见的,两者之间还有什么区别?
编辑:
没有人领取赏金,我想更进一步,但我不确定问题出在哪里。有人建议好的起点吗?
编辑:类
> Foo.new.jids.class
=> Array
> BarWorker.perform_in(10.minutes, 1).class
=> String
> FooMailer.delay_for(10.minutes).confirm_foo(self).class
=> String
编辑:
这是我的分析...
jids
是 Foo
class 成员...以及 sidekiq 在后台工作的方式(使用 celluloid 功能不允许竞争条件并避免死锁和一堆我不知道的其他功能)..让它在后台线程中完成大部分工作...
如果我的分析是正确的...那么日志记录可能如下所示
foo = Foo.new
foo.do_job
# logs show the following
["s", "243675806204134e6f05abaa"]
["s", "1444f558d7582df1000c6f4b", "c0878213a8ea5f783c30e666"]
foo.jids
=>["s", "243675806204134e6f05abaa"]
foo.reload
foo.jids
=>["s", "243675806204134e6f05abaa", "I'm new here"]
虽然 test_jids
是一个本地数组,可能会在方法结束之前使用...这就是它立即返回的原因..(这就是为什么您的解决方法有效的原因:D 有事可做线程的工作方式)...
如有错误请指正... 如果我没记错的话...您需要更多详细信息...您必须深入了解 sidkiq 和 celluloid 如何管理它们的线程
也看看下面的
我认为这是因为 Rails 缓存了除序列化字段之外的所有列类型的属性。考虑到这一点,当您在 getter 上为 jids
调用 <<
方法时,Rails 会获取该字段的属性,但是当您将 self
传递给邮件程序在 Sidekiq 中序列化时再次调用 getter,并覆盖属性实例,因此返回值不会添加到正确的 jids 实例中。
我不确定我是否完全理解为什么会发生这种情况,所以一些具体的实施细节可能不太准确!
这可以 fixed/made 通过以下方式之一使用此版本的 Rails (4.1.5):
缓存 jids
属性:
class Foo < ActiveRecord::Base
serialize :jids, Array
cache_attributes :jids
使用 jids
setter:
jids = self.jids << FooMailer.delay_for(10.minutes).confirm_foo(self)
将 id
或副本传递到邮件程序中:
jids << FooMailer.delay_for(10.minutes).confirm_foo(id)
# or
jids << FooMailer.delay_for(10.minutes).confirm_foo(self.dup)
这在 Rails 4.2 中已修复,当此代码被重写时,我可以找到一个 PR:https://github.com/rails/rails/pull/15429