延迟任务创建无法访问某些python模块的新实例

Jab*_*key 5 python google-app-engine google-cloud-endpoints

我使用最新版本的GAE,具有自动缩放,端点API和deferred.defer()任务.

问题是,自从添加API以来,有些实例会自动启动,总是会导致永久性任务失败:

Permanent failure attempting to execute task
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: No module named app.Report
Run Code Online (Sandbox Code Playgroud)

永久任务失败对于单个实例是唯一的,其中该实例上的每个延迟任务都会失败.即使任务未使用Api.py模块,这些延迟任务都会抛出相同的错误.在其他情况下,如果未将任何路由到故障实例,则相同的延迟任务将正常运行.

app.yaml处理程序看起来像这样:

handlers:
# Api Handler
- url: /_ah/api/.*
  script: main.api
- url: /_ah/spi/.*
  script: main.api
# All other traffic
- url: .*
  script: main.app

builtins:
- deferred: on
Run Code Online (Sandbox Code Playgroud)

main.py看起来像:

import Api, endpoints, webapp2

api = endpoints.api_server([Api.AppApi])

app = webapp2.WSGIApplication( 
    [(misc routes)]
,debug=True)
Run Code Online (Sandbox Code Playgroud)

Api.py看起来像:

import endpoints
from protorpc import messages
from protorpc import message_types
from protorpc import remote
from google.appengine.ext import deferred
from app.Report import ETLScheduler

@endpoints.api(...)
class AppApi(remote.Service):
    @endpoints.method(...)
    def reportExtract(self, request):
        deferred.defer(
            ETLScheduler,
            params
        )
Run Code Online (Sandbox Code Playgroud)

我没有做任何路径修改,所以我很好奇为什么新实例无法找到API的python模块,即使延迟任务在另一个使用其他功能的模块中.为什么它只会为该实例抛出这些错误?

编辑:

因此,在查看了其他一些SO问题之后,我尝试进行路径修改appengine_config.py.我将所有文件夹移动到一个lib目录,并将其添加到配置文件中:

import os,sys
sys.path.append(os.path.join(os.path.dirname(__file__), 'lib'))
Run Code Online (Sandbox Code Playgroud)

现在我在失败的实例上得到的错误是:

Permanent failure attempting to execute task
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: cannot import name ETLScheduler
Run Code Online (Sandbox Code Playgroud)

所以它似乎找到了模块,但与之前一样,实例上的延迟任务都不能导入该方法.

Jab*_*key 1

所以我想出了一种让它发挥作用的方法,但不确定为什么它会起作用。

通过导入整个模块,而不是模块中的方法,为延迟任务启动的新实例不再抛出错误PermanentTaskFailure: cannot import name ETLScheduler

我尝试导入整个模块而不是方法,以便 Api.py 看起来像这样:

import endpoints
from protorpc import messages
from protorpc import message_types
from protorpc import remote
from google.appengine.ext import deferred

# Import the module instead of the method
#from app.Report import ETLScheduler
import app.Report

@endpoints.api(...)
class AppApi(remote.Service):
    @endpoints.method(...)
    def reportExtract(self, request):
        deferred.defer(
            app.Report.ETLScheduler,
            params
        )
Run Code Online (Sandbox Code Playgroud)

现在我不再收到抛出PermanentTaskFailure: cannot import name ETLScheduler. 通过在 main.py 中导入 Api.py 可能是循环依赖(我不确定),但至少它现在可以工作。