【问题标题】:How can I create a script that picks up where it left off in case of failure?如何创建一个脚本,在失败的情况下从中断的地方继续?
【发布时间】:2013-12-06 21:35:29
【问题描述】:

我正在编写一个在 AWS 中自动创建大量资源的脚本(除了一些其他任务之外),但是开发和测试非常耗时,因为我只能一直走到最后让脚本失败,然后我必须更正错误并再次运行脚本。

是否有任何 shell 脚本工具(unix 或 ruby​​ 甚至 Windows),如果发生故障,我可以在其中启动脚本?也许有一些方法可以让rake 运行一个没有所有依赖任务的任务?

更新:

为了澄清,我不是在寻找任何在调用之间保持状态的复杂的东西;我说的是编写一个简单的 shell 脚本,其中可能包含几十个连续的步骤,每个步骤都需要很长时间。换句话说,如果脚本在第 10 步崩溃了,我想在第 10 步再次启动脚本,而不必重新运行之前的所有步骤。

【问题讨论】:

  • Ruby 不支持这一点,我知道的任何其他语言也不支持。有一个基于核心转储的 Perl“可执行文件”,但它总是从应用程序的开头开始,而不是在所有解释器状态完好无损的任意位置。编写不断监视和保存正在运行的程序的可变状态的代码将是高度侵入性的。虽然这是可能的,但该程序在生产环境中会非常缓慢且无法使用,至少在当前计算机的速度下是这样。此外,如果程序崩溃了,您将如何解决问题并重新启动?
  • 真的归结为您需要构建您的应用程序以允许在没有运行任何先前例程的情况下跳转到特定例程。

标签: ruby shell scripting rake


【解决方案1】:

一种常见的轻量级方式是使用日志文件。

基本上,您为每个执行的条目在日志文件中写入一行。

例如:

  • <some_id> OK
  • <some_id> ERROR <some_reason>

这样,您可以通过执行grep OK /tmp/script.log | tail -n 1grep ERROR /tmp/script.log 的所有错误来获得最后一个“有效状态”

此解决方案的一个好处是您可以阅读所有行,只需在它们上调用#.to_i。这样你就很容易拿到id了。

如果您有几百万个条目,您的文件会变得相当多,但之后您可以将其丢弃。

【讨论】:

  • 这无助于重新启动应用程序,该应用程序处于死亡/崩溃/被杀死之前的特定步骤。
  • 好吧。 1.当你看到它崩溃时你必须修复你的应用程序,然后你可以在所有失败的id上运行它。或者在最后一个执行的 id 处重新启动。我的方法非常轻量,不像填充数据库那样复杂,但在每台计算机上都可用。
【解决方案2】:

你需要在你前进的过程中保持你的进步状态,这样你就知道从哪里重新开始。

不过,这种坚持可能是一百万件事。它可能是您连接的数据库、您写入的文件、memcached 服务器。

所以这真的取决于你在做什么,你需要记录什么数据,以及你可以访问什么数据持久性。


如果您有一个用于存储记录的数据库,这将像以下内容一样简单:

MyThing.where(uploaded: false).each do |thing|
  thing.upload!
  thing.update_attribute uploaded: true
end

如果中途失败,它会从中断的地方继续,因为它正在标记完整的记录。

【讨论】:

  • 我在大型 RSS 聚合器上做过类似的事情,这标志着提要更新的进度,所以如果它死了,它可以从中断的地方继续。但是,这与从应用程序的正常开头开始并没有什么不同,它只是在运行时需要处理的记录数量减少。
  • @theTinMan 您是否希望脚本自动减少它应该做的工作量?错误就是错误。自我修复应用是未来的一些梦想。
  • 我不希望脚本除了运行之外什么都不做。它的运行方式取决于开发人员。我编写的代码必须处理数千个提要,并且在停止后可以恢复。如果它是一个错误,它可能会崩溃,但在修复它之后我可以重新启动它,它会在它正在处理的同一个提要上起飞。可以在预定义的点重新启动,但不能在任意点重新启动。
  • 我确实记得几年前 Dylan 在 Apple 之外的演讲和演示,我认为他们说它能够在出现错误并注入新代码后重新启动。这可能是一个冒险的步骤,因为在那个时候变量状态可能会被搞砸。
猜你喜欢
  • 1970-01-01
  • 2013-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多