[英]How can I ensure that calling #changed? on an instance of an ActiveRecord model after a transaction rolls back returns true?
[英]How can I ensure that ActiveRecord is saving changes to the database
我有一个复杂的系统,涉及许多Resque工人,工作和监视过程。 这些作业具有父子依赖关系,并且它们通过一系列状态(使用state-machine )运行,这就是监视过程的原因。 我们依靠数据库状态来确保跨进程跟踪是同步的。
这是一个大概的想法:
class ParentMonitor < ActiveRecord::Base
has_many children, class: ChildMonitor
state_machine :state, initial: :work_needed do
event :succeed do
transition :work_needed => :work_succeeded
end
event :fail do
transition :work_needed => :work_failed
end
end
def child_transition
return if children.any? { |child| child.work_needed? }
if children.any? { |child| child.work_succeeded? }
succeed
else
fail
end
end
end
class ChildMonitor < ActiveRecord::Base
belongs_to: owner, class: ParentMonitor
state_machine :state, initial: :work_needed do
event :succeed do
transition :work_needed => :work_succeeded
end
after_transition :to => :work_succeeded, :do => :notify_owner
event :fail do
transition :work_needed => :work_failed
end
after_transition :to => :work_failed, :do => :notify_owner
end
def notify_owner
owner.child_transition
end
end
发生的事情是,对于前几个这样的工作(例如,数百个工作中有十二个或两个),即使所有孩子都处于work_succeeded
或work_failed
状态, work_needed
仍处于work_needed
状态。 通过跟踪和测试,我确定每次调用ParentMonitor#child_transition
,都将依次减少处于“需要工作”状态的子级列表,直到在某个时候它会加载数据库并将所有子级替换为“需要的工作”。 即使某些内容以前已经完成。
另外,直到它突然开始记录更新之前,我在前几个孩子的日志文件中看不到任何UPDATE
日志。 该日志记录与似乎要重置其所有子状态的记录同时进行。
它使我认为更改是由于某种缓存状态而在内存中发生的,但是我在整个过程中添加了reload
, save
和find
调用,它们似乎并没有影响更改。 我也尝试过将这些调用包装在非uncache
但这无济于事。
事实证明这是由该写了在长时间运行的事务举行,因为状态机宝石保持打开的状态变化和任何结束之间的交易造成的事实after
挂钩。 我们已经编写了在主要监视循环中运行了几个小时的钩子。
我们通过在状态更改之间而不是在回调中执行操作来解决此问题。
顺便说一句,错误行为与最新的《 红皮书》完全相同,这是在大多数RDMBS中实现的“弱隔离”并发的副作用:
异常示例包括读取另一个事务产生的中间数据,读取中止的数据,在执行同一事务期间读取同一项目的两个或多个不同值,以及由于并行写入同一项目而“丢失”事务的某些影响
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.