PermanentTaskFailure: __new__() 正好需要 4 个参数(由于 DateTimePropety?)

PermanentTaskFailure: __new__() takes exactly 4 arguments (due to DateTimePropety?)

"Background work with the deferred library" 文章之后,我创建了一组计划任务来帮助维护我们的应用程序。他们各自刷新特定类型的旧实体。

在一种情况下,我们不使用标准的 ndb 模型 key 属性(用于跟踪哪些记录已被处理),而是使用 属性 类型的非键 属性 =16=]。当我们这样做并命中 DeadlineExceededError 时,该方法的延迟实例在 deferred.run method.

中生成的任务参数解封期间终止

我们基地的相关代码class:

def _continue(self, start_key, batch_size):
    # ...
    except DeadlineExceededError:
        if self._numBatches > 0:
            self.Log("Deferring to a new instance of the process.")
            deferred.defer(self._continue, start_key, batchSize)
        else:
            self.LogWarning("No batches were completely processed. This process will terminate to prevent continuous operation.")
            raise deferred.PermanentTaskFailure("DeadlineExceededError occurred before any batches could be completely processed.")
    self.Finish()

当方法的延迟副本启动时,它会产生此错误:

Traceback (most recent call last):
    File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/deferred/deferred.py", line 310, in post
        self.run_from_request()
    File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/deferred/deferred.py", line 305, in run_from_request
        run(self.request.body)
    File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/deferred/deferred.py", line 145, in run
        raise PermanentTaskFailure(e)
    PermanentTaskFailure: __new__() takes exactly 4 arguments (1 given)

更多挖掘(pdb 通过 deferredpickle 库)揭示更多细节:

1080        def load_newobj(self):
1081            args = self.stack.pop()
1082            cls = self.stack[-1]
1083 ->         obj = cls.__new__(cls, *args)
1084            self.stack[-1] = obj
1085        dispatch[NEWOBJ] = load_newobj

(Pdb) pp args
      ()
(Pdb) pp cls
      <class 'google.appengine.ext.ndb.query.FilterNode'>
(Pdb) n
      TypeError: '__new__() takes exactly 4 arguments (1 given)'
      > /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py(1083)load_newobj()

我会深入挖掘,但现在的基本问题似乎是:

  1. 除了 pdb 之外,如何才能获得有关此阶段发生的故障的更多信息(即:deferred.run 和 unpickling)?
  2. 我在网上找到了一些关于覆盖 deferred.TaskHandler 能力的提示(在 v.1.6.3 - Feb 28, 2012 中介绍),这可能有助于解决第一个问题,但找不到任何关于如何执行此操作的示例。
  3. 似乎带有 DateTimeProperty 的 ndb FilterNodes 在默认情况下可能无法挑选(或正确处理)。是这样吗?

deferred.py 的来源可以看出,您已经与 @rdodev 一起分析得很好,意识到问题出在尝试将 data 参数解封为 run()。反过来,它是从 run_from_request() 调用的,所以这里未 pickle 的是请求有效负载本身,它是在您调用 deferred.defer() 时创建的。

可能要取消 pickled DateTimeProperty,pickle 模块需要为其调用构造函数 (__new__),但这不可用或提供了不同的方法当时的签名比它被腌制时的签名,导致你看到的异常,它冒泡被捕获并呈现给你 PermanentTaskFailure.

总的来说,如果您可以生成一个可靠地重现该行为的示例应用程序,那么这可能值得作为缺陷报告发布给 public issue tracker

除此之外,作为目前的解决方法,我会使用不会导致错误的内容,例如 DateTimeProperty 的字符串表示形式或常规 datetime.datetime 对象,甚至另一个 ndb.Property class 不会导致问题。您也可以尝试使用 taskqueue library 本身,它非常易于使用并且不会与您当前的用例有重大差异。