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
通过 deferred
和 pickle
库)揭示更多细节:
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()
我会深入挖掘,但现在的基本问题似乎是:
- 除了 pdb 之外,如何才能获得有关此阶段发生的故障的更多信息(即:deferred.run 和 unpickling)?
- 我在网上找到了一些关于覆盖
deferred.TaskHandler
能力的提示(在 v.1.6.3 - Feb 28, 2012 中介绍),这可能有助于解决第一个问题,但找不到任何关于如何执行此操作的示例。
- 似乎带有 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 本身,它非常易于使用并且不会与您当前的用例有重大差异。
在 "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
通过 deferred
和 pickle
库)揭示更多细节:
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()
我会深入挖掘,但现在的基本问题似乎是:
- 除了 pdb 之外,如何才能获得有关此阶段发生的故障的更多信息(即:deferred.run 和 unpickling)?
- 我在网上找到了一些关于覆盖
deferred.TaskHandler
能力的提示(在 v.1.6.3 - Feb 28, 2012 中介绍),这可能有助于解决第一个问题,但找不到任何关于如何执行此操作的示例。 - 似乎带有 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 本身,它非常易于使用并且不会与您当前的用例有重大差异。