【问题标题】:@monthly cron job is not reliable@monthly cron 工作不可靠
【发布时间】:2018-04-23 12:22:07
【问题描述】:

我们的客户希望我们每月创建一份报告。

过去,我们使用@monthly cron 作业来执行此任务。

但这并不可靠:

  1. 服务器可能在这一分钟内关闭。 Cron 不会重新运行这些作业
  2. 如果服务器已启动,则此时可能无法访问数据库。
  3. 如果服务器已启动且数据库已启动,则可能存在无法访问的第三方系统
  4. 可能存在软件错误。

我该怎么做才能确保每月创建报告?

这是一个基于 Django 的网络应用程序

【问题讨论】:

  • 为此,您需要一些可靠的方法来跟踪创建报告的成功尝试。您是否考虑过使用类似ReportCreationLog 的模型来记录数据库中的成功尝试?这样您就可以确保满足您的所有条件。
  • @Cole 是的,你是对的。我想我什至不需要日志。我可以检查结果是否已经可用。

标签: python django cron


【解决方案1】:

使用合适的调度器

celery beat 是一个调度器;它定期启动任务,然后由集群中可用的工作节点执行。

您使用报告功能作业创建定期任务。如果作业失败,celery 将按照您设置的重试策略重试。

Celery doc - Periodic Tasks

【讨论】:

  • 我曾经用芹菜工作过。感觉又大又复杂。对于我当前的用例,功能较少的工具可能会更好。不过还是谢谢你的回答。我投了赞成票。
  • 感谢您的支持。我一直用 Celery,觉得没问题,所以我不能再帮你了。
  • @guettli,一开始可能会觉得很大,但是一旦设置了包并且可选的daemonization 就位,Django 项目中的实际代码非常短。
【解决方案2】:

您应该编写一些脚本来测试条件并执行所有必需的操作。

if is_work_finished_less_then_month_ago():
    return
else:
    try:
        generate_normal_report()
    except some_error as e:
        report_about_error(e)

然后每小时或每天运行一次。

如果你害怕error_reports太多,那么在report_about_error()方法中做同样的事情:检查你上次发送报告的时间,如果太频繁就不要发送。

【讨论】:

  • 这与幂等性有关吗?我曾经在 celery 文档中读过这个:docs.celeryproject.org/en/latest/glossary.html#term-idempotent
  • @guettli 是的,它是一个可以在不改变结果的情况下多次调用的函数。实际上,这意味着一个功能可以重复多次而不会产生意外影响,但不一定是纯粹意义上的无副作用»。
  • 是的,我可以用芹菜。但我喜欢这个简单的解决方案。我可以每六个小时运行一次这项工作。如果在午夜失败,它将在 6 点重新运行。
【解决方案3】:

移动部件太多,因此需要考虑的选项。但是问题 1 意味着您需要某种形式的外部方式来跟踪成功(否则一个选项将是您的服务器任务 - 例如 bash 脚本 - 继续重试 N 次并在重试之间休眠,直到报告生成成功)。

如果您想要一个成熟的解决方案,可用于满足许多不同的未来需求,您可以查看可用的第三方调度程序,例如 Jenkins 或 SOS Berlin。

如果您正在寻找更简单的解决方案,您可以通过 cron 安排报告脚本运行多次(比如在月底的几天内每小时运行一次),然后让它跟踪报告是否生成并成功发送(这可以像创建文件并检查其存在或将值写入数据库一样简单)。

【讨论】:

  • 我完全同意“更简单的解决方案”。但如果存在软件错误,则可能会发送或创建多个报告。这个问题只有两种解决方案:1) 编写没有错误的正确软件,或 2) 不编写软件。
【解决方案4】:

简单的方法是您可以编写一个帮助程序,以便脚本首先检查报告的可用性,并仅在报告不可用时生成报告。

然后安排脚本在每月的那一天每小时运行一次。

如下更改您的脚本:

if [[ -f <report_name> ]]
then
    echo "report exists" 
    exit 1
else
    echo "run generate report script"

crontab 条目(每月 28 日每小时运行一次):

0 0-23 28 * * <name_of_helper_script>

【讨论】:

    【解决方案5】:

    cron 无法满足您的要求。并且通过您的 Django 应用程序启动类似 cron 的任务并不是 Django 的创建目的,并且只有在您处理所有边缘情况并确保在您的应用程序出现故障时捡起错过的运行等情况下才能工作。这将是一个错误处理、状态管理和并发注意事项的兔子洞。

    我会建议以下两种选择之一:

    • 无论如何都要使用 cron 开始工作,但要编写 Nagios 检查以确保在由于某种原因未生成报告时通知您(并手动处理那些罕见的情况)。
    • 使用Airflow 或任何其他专门为处理计划任务的调度、监控、重试和日志记录而创建的框架。

    如果这真的是一次性工作,那么前者就是你想要的。如果您有更多这样的任务,后者会更好。

    【讨论】:

    • Apache Airflow 看起来功能非常丰富。我想它有一个有效的用例。就我而言,它太大了。
    • 在这种情况下,我建议将 cron 作为简单的解决方案,然后监控报告是否实际生成。这比设计一个不会失败的系统要容易得多。
    • 在考虑了“幂等性”这个词之后……我可以每小时调用一个脚本。如果报告存在,它什么也不做。如果没有,则创建输出。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多