简体   繁体   English

如何确保ActiveRecord将更改保存到数据库

[英]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_succeededwork_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. 它使我认为更改是由于某种缓存状态而在内存中发生的,但是我在整个过程中添加了reloadsavefind调用,它们似乎并没有影响更改。 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.

相关问题 如何确保致电已更改? 事务回滚后在ActiveRecord模型的实例上返回true? - How can I ensure that calling #changed? on an instance of an ActiveRecord model after a transaction rolls back returns true? 如何在Rails / ActiveRecord中的事务之外执行数据库操作 - How can I execute a Database Operation outside of a transaction in Rails / ActiveRecord 我无法在 Activerecord 中复制此数据库 model - I can't replicate this database model in Activerecord 我可以使用ActiveRecord在数据库中存储Rails单词列表吗? - Can I store a Rails wordlist in database with ActiveRecord? ActiveRecord SQL Server适配器未保存事务中的更改 - ActiveRecord SQL Server Adapter not saving changes in transaction 在Rails 3中,如何确保在加载模型之前将枚举表加载到测试数据库中? - In rails 3, how can I ensure enum tables are loaded into the test database before models load? 如何确保 Sidekiq 后台作业针对它们启动的同一数据库运行 - How can I ensure Sidekiq background jobs run against the same database they were initiated from 如何在没有数据库的情况下模拟ActiveRecord模型规范中的唯一性验证错误? - How can I simulate a uniqueness validation error in an ActiveRecord model spec without the database? 如何获得独立的ActiveRecord :: Base工具连接到生产数据库? - How can I get my stand alone ActiveRecord::Base tool to connect to my production database? 如何永久忽略ActiveRecord :: Base类中的数据库列? - How can I permanently ignore a database column in my ActiveRecord::Base class?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM