【问题标题】:What's the most effective way to execute a task some distant time in the future on App Engine?将来在 App Engine 上执行某项任务的最有效方法是什么?
【发布时间】:2013-02-05 21:05:07
【问题描述】:

我在 App Engine 上有一个应用程序正在消耗一些数据。解析该数据后,它会知道它需要在一段时间内执行某项操作 - 可能不会持续数小时或数周。

在 App Engine 上一段时间后执行一段代码的最佳方式是什么?

我认为使用 TaskQueue 中的 Countdown Millis 或 EtaMillis 会起作用,但没有看到任何证据表明有人在做同样的事情,尤其是在如此长的时间范围内。

这是最好的方法,还是有更好的方法?

【问题讨论】:

    标签: java google-app-engine scheduled-tasks scheduling


    【解决方案1】:

    如果您能够将对象与所有相关信息保存在数据存储中以供将来处理(包括何时开始处理对象数据),您可以让一个 cron 作业定期查询数据存储,其中包含日期/时间范围过滤并在适当的时间触发处理上述任何对象。

    【讨论】:

      【解决方案2】:

      我们成功地使用 TaskQueue 的倒计时参数在客户注册 7 天后向客户发送电子邮件以及满足其他需求。

      任务队列是核心/基本 API/服务,非常可靠 - 我认为这是使用任务队列 ETA/倒计时的最佳方式,除非您:

      • 需要能够以编程方式查看队列中的内容
      • 需要能够以编程方式从队列中删除某些任务

      【讨论】:

        【解决方案3】:

        我将任务队列用作调度程序。在QueueConstants 中声明并在QueueImpl 中应用了 30 天的最大 eta。

          //Returns the maximum time into the future that a task may be scheduled.
          private static final long MAX_ETA_DELTA_MILLIS = 2592000000L;
        

        1000ms * 60s * 60m * 24hr * 30days = 2592000000ms

         private long determineEta(TaskOptions taskOptions) {
        Long etaMillis = taskOptions.getEtaMillis();
        Long countdownMillis = taskOptions.getCountdownMillis();
        if (etaMillis == null) {
          if (countdownMillis == null) {
            return currentTimeMillis();
          } else {
            if (countdownMillis > QueueConstants.getMaxEtaDeltaMillis()) {
              throw new IllegalArgumentException("ETA too far into the future");
            }
            if (countdownMillis < 0) {
              throw new IllegalArgumentException("Negative countdown is not allowed");
            }
            return currentTimeMillis() + countdownMillis;
          }
        } else {
          if (countdownMillis == null) {
            if (etaMillis - currentTimeMillis() > QueueConstants.getMaxEtaDeltaMillis()) {
              throw new IllegalArgumentException("ETA too far into the future");
            }
            if (etaMillis < 0) {
              throw new IllegalArgumentException("Negative ETA is invalid");
            }
            return etaMillis;
          } else {
            throw new IllegalArgumentException(
                "Only one or neither of EtaMillis and CountdownMillis may be specified");
          }
        }
        

        }

        【讨论】:

          【解决方案4】:

          我执行以下操作:

          1. 使用您提到的配置延迟将任务排入队列。让任务处理以已知方式更改数据存储条目(例如:设置标志)。

          2. 有一个散乱的低频 cron 作业,以执行任何被排队任务以某种方式遗漏的处理(例如:任务中发生未捕获的异常)。

          为此,请确保任务和 cron 作业调用的处理是幂等的。

          喜欢吗?

          【讨论】:

            【解决方案5】:

            我认为taskQueue是一个很好的策略,但有一个大问题“如果一个推送任务创建成功,它最终会被删除(最多在任务成功执行后7天)。” Source

            我会改用datastore。这是您可以采取的一种策略:

            1. 完成“解析该数据”后,将记录插入数据存储区。
            2. 根据创建/插入日期检查当前日期,以查看自您的工作完成/开始等以来已经过去了多少时间 (很明显,你不想每分钟都做,等可能做一次 每天或每小时)
            3. 一旦第 2 步中的条件超过了您想要的“任意时间”,就执行您需要执行的下一个任务。

            以下是如何将记录添加到数据存储中...帮助您入门..

                Entity parsDataHolder = new Entity("parsing_data_done", guestbookKey);
                parsDataHolder.setProperty("date", date);
            
            DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
            datastore.put(parsDataHolder)
            

            【讨论】:

            • 这将导致运行一个后端实例......连续一周,仅用于一项任务。这似乎有点低效。
            • @JonathanNewmuis 你对我的第一个回答是正确的,我更新了我的回答。感谢您花时间帮助我改进我的答案。另外,如果你投票给我,那也会让我振作起来:)
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-08-05
            • 1970-01-01
            • 1970-01-01
            • 2015-12-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多