[Alt](https://res.cloudinary.com/practicaldev/image/fetch/s--qvbxA48p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev- to-uploads.s3.amazonaws.com/i/fdncjl2tm3jw7k3epr70.gif)

我知道,我怎么敢建议在生产中运行脚本。我是一名站点可靠性工程师,我绝不应该容忍这种疯狂行为。但事实是,有时您可能需要在生产环境中运行脚本来更新或清理一些数据。在这篇文章中,我将为您提供一些关于如何在生产环境中尽可能安全地编写和执行脚本的提示。

1) 跟踪您的进度

没有什么比编写一大段代码更糟糕的了,将其粘贴到控制台中,然后按回车键并看着它坐在那里。您不知道代码在脚本中的什么位置或它在做什么,至少对我来说,这很可怕。

出于这个原因,您总是希望确保从脚本中输出某种进度表。这使您可以跟进并了解您在流程中的位置。如果您使用 Ruby,请考虑一些放置良好的 puts 语句。下面是我们最近在 DEV 使用的一个脚本,用于清理一些不正确的缓存数据。请注意整个脚本中的 puts 语句,它们允许我们在其工作时跟随它。

invalid_articles = []
Tag.where(id: tag_ids).find_each do |tag|
  puts tag.taggings.count

  tag.taggings.each_with_index do |tagging, index|
    puts index if index%100 == 0
    article = tagging.taggable
    next unless article

    result = article.update(cached_tag_list: article.tags.pluck(:name).join(", "))
    if result
      puts "Artcle update success #{article.id}"
    else
      puts "Artcle update failure #{article.id}"
      invalid_articles << article
    end
  end
end

进入全屏模式 退出全屏模式

另请注意,我们正在跟踪运行此脚本时可能发现的任何无效文章。尤其是当您清理不良数据时,请始终假设您可能会偶然发现更多数据并在脚本中为此做好准备。在这里,我们使用if/else语句来捕获任何无效文章。您也可以使用begin/rescue块。

2) 记录状态前后

当您更新记录时,总会有一些事情会脱轨。为了能够在您进行更新时“回滚”跟踪您之前的状态。如果我们更新上面的脚本来做到这一点,这就是它的样子。

invalid_articles = []
before_update_tag_lists = {} 
Tag.where(id: tag_ids).find_each do |tag|
  tag.taggings.each_with_index do |tagging, index|
    puts index if index%100 == 0
    article = tagging.taggable
    next unless article
    # Record the current cached tag list for every article
    before_update_tag_lists[article.id] = article.cached_tag_list

    result = article.update(cached_tag_list: article.tags.pluck(:name).join(", "))
    if result
      puts "Artcle update success #{article.id}"
    else
      puts "Artcle update failure #{article.id}"
      invalid_articles << article
    end
  end
end

进入全屏模式 退出全屏模式

如果此脚本运行时出现任何问题,则before_update_tag_lists哈希中包含我们所有的原始数据。使用这些原始数据,我们可以循环浏览文章,并在必要时使用旧列表重新更新它们。

3) 编写生产质量代码

当您编写脚本以使用尽可能少的语法时,这可能很诱人。通常,这意味着在任何地方都放入单个字母变量。你可能永远不会再使用这段代码了,那么为什么要浪费时间让它看起来漂亮和可读呢?你想让它变得漂亮和可读的原因是因为这样脚本更容易理解和遵循。拥有易于理解的脚本将帮助您避免编写错误。

在上面的脚本示例中,我清楚地写出了我正在使用的每个对象。这使得几乎任何人都可以查看脚本并能够理解它在做什么。这引出了我的下一个脚本写作技巧。

4) 审核您的脚本

就像你永远不想在没有代码审查的情况下将代码推送到生产环境一样,你不应该在没有代码审查的情况下在生产环境中运行脚本。这是您希望确保脚本易于理解和可读的另一个原因,因为您希望其他人也能够弄清楚它在做什么。

我们都知道第二双眼睛对我们的代码带来的价值。即使您发现自己处于时间紧迫并且需要尽快运行脚本的情况下,也请尽可能多地关注它。我无法告诉你有多少次新的眼睛让我没有搞砸脚本更新。

5) 使用屏幕或Tmux用于长时间运行的脚本

Tmux 和 Screen 允许您在 shell 中启动 ssh 会话,即使在网络中断的情况下也可以保持该 shell 处于活动状态。这可确保如果您在脚本运行时断开连接,脚本运行不会被中断。感谢@kinduff的提醒!

kinduff 个人资料图片Alejandro AR•20 年 6 月 17 日

如果该任务需要很长时间,您就有可能与 SSH 会话、您的 Internet 提供商等断开连接。

为避免这种情况,我建议使用 screen.js 运行这些脚本(尽管我根本不建议运行这样的脚本)。它非常易于使用:

  1. SSH 进入所需的实例

  2. 使用screen开始一个新的屏幕会话

3.运行长时间运行的脚本

  1. Ctrl+a然后按d分离会话

  2. 您现在可以关闭所有内容,包括 SSH 会话

  3. 您可以使用screen -r重新附加到屏幕会话

Screen 有很多很棒的东西,请务必查看手册页。

在生产中运行脚本从来都不是理想的,但如果你在执行时使用这些技巧,它可以让体验变得不那么令人生畏。

快乐的脚本!

Logo

CI/CD社区为您提供最前沿的新闻资讯和知识内容

更多推荐