[英]How can I ensure that ActiveRecord is saving changes to the database
I have a complex system that involves many Resque workers, jobs, and a monitoring process. 我有一个复杂的系统,涉及许多Resque工人,工作和监视过程。 The jobs have parent-child dependencies and these run through a series of states (using state-machine ), which is the reason for the monitoring process.
这些作业具有父子依赖关系,并且它们通过一系列状态(使用state-machine )运行,这就是监视过程的原因。 We depend on the database state to ensure that cross-process tracking is in sync.
我们依靠数据库状态来确保跨进程跟踪是同步的。
Here's a rough idea: 这是一个大概的想法:
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
What's happening is that for the first few such jobs (say a dozen or two out of several hundred), the ParentMonitors are being left in the work_needed
state even though all children are either in work_succeeded
or work_failed
. 发生的事情是,对于前几个这样的工作(例如,数百个工作中有十二个或两个),即使所有孩子都处于
work_succeeded
或work_failed
状态, work_needed
仍处于work_needed
状态。 Through tracing and testing I've determined that each the time ParentMonitor#child_transition
is called, the list of children in "work needed" state has successively been reduced until at some point it makes a database load and replaces all the children with values of "work needed". 通过跟踪和测试,我确定每次调用
ParentMonitor#child_transition
,都将依次减少处于“需要工作”状态的子级列表,直到在某个时候它会加载数据库并将所有子级替换为“需要的工作”。 Even though some had previously been completed. 即使某些内容以前已经完成。
In addition I don't see any UPDATE
logs in the log file for these first few children until it suddenly starts logging the updates. 另外,直到它突然开始记录更新之前,我在前几个孩子的日志文件中看不到任何
UPDATE
日志。 That logging is simultaneous with when it seems to reset the states of all its children. 该日志记录与似乎要重置其所有子状态的记录同时进行。
It makes me think that the changes are all happening in memory due to some cached state, but I've added reload
, save
and find
calls throughout and they don't seem to effect change. 它使我认为更改是由于某种缓存状态而在内存中发生的,但是我在整个过程中添加了
reload
, save
和find
调用,它们似乎并没有影响更改。 I've also tried wrapping these calls in uncache
but that doesn't help. 我也尝试过将这些调用包装在非
uncache
但这无济于事。
As it turned out this was caused by the fact that the writes were held in a long-running transaction because the state-machine gem holds open a transaction between the state change and the end of any after
hooks. 事实证明这是由该写了在长时间运行的事务举行,因为状态机宝石保持打开的状态变化和任何结束之间的交易造成的事实
after
挂钩。 We had written hooks that ran for hours on the main monitoring loop. 我们已经编写了在主要监视循环中运行了几个小时的钩子。
We resolved this by performing the actions between state changes rather than in callbacks. 我们通过在状态更改之间而不是在回调中执行操作来解决此问题。
Incidentally, the erroneous behavior is exactly as described in the latest Red Book as a side-effect of "weak isolation" concurrency implemented in most RDMBS's: 顺便说一句,错误行为与最新的《 红皮书》完全相同,这是在大多数RDMBS中实现的“弱隔离”并发的副作用:
example anomalies include reading intermediate data that another transaction produced, reading aborted data, reading two or more different values for the same item during execution of the same transaction, and “losing” some effects of transactions due to concurrent writes to the same item
异常示例包括读取另一个事务产生的中间数据,读取中止的数据,在执行同一事务期间读取同一项目的两个或多个不同值,以及由于并行写入同一项目而“丢失”事务的某些影响
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.