Python DeadlineExceededError:已超过响应HTTP请求的总截止日期
我有一个cron作业,它调用供应商api来获取公司列表。获取数据后,我们将数据存储到云数据存储中,如下面的代码所示。出于某种原因,在我触发cron作业的前两天,我开始看到错误。当我在本地调试代码时,我没有看到这个错误Python DeadlineExceededError:已超过响应HTTP请求的总截止日期,python,google-app-engine,google-cloud-datastore,google-cloud-platform,Python,Google App Engine,Google Cloud Datastore,Google Cloud Platform,我有一个cron作业,它调用供应商api来获取公司列表。获取数据后,我们将数据存储到云数据存储中,如下面的代码所示。出于某种原因,在我触发cron作业的前两天,我开始看到错误。当我在本地调试代码时,我没有看到这个错误 company_list = cron.rest_client.load(config, "companies", '') if not company_list: logging.info("Company list is empty")
company_list = cron.rest_client.load(config, "companies", '')
if not company_list:
logging.info("Company list is empty")
return "Ok"
for row in company_list:
company_repository.save(row,original_data_source,
actual_data_source)
存储库代码
def save( dto, org_ds , act_dp):
try:
key = 'FIN/%s' % (dto['ticker'])
company = CompanyInfo(id=key)
company.stock_code = key
company.ticker = dto['ticker']
company.name = dto['name']
company.original_data_source = org_ds
company.actual_data_provider = act_dp
company.put()
return company
except Exception:
logging.exception("company_repository: error occurred saving the
company record ")
raise
错误
例外情况详细信息
Traceback (most recent call last):
File
"/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/googl
e/appengine/runtime/wsgi.py", line 267, in Handle
result = handler(dict(self._environ), self._StartResponse)
File "/base/data/home/apps/p~svasti-173418/internal-
api:20170808t160537.403249868819304873/lib/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "/base/data/home/apps/p~svasti-173418/internal-
api:20170808t160537.403249868819304873/lib/flask/app.py", line 1817, in
wsgi_app
response = self.full_dispatch_request()
File "/base/data/home/apps/p~svasti-173418/internal-
api:20170808t160537.403249868819304873/lib/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/base/data/home/apps/p~svasti-173418/internal-api:20170808t160537.403249868819304873/lib/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/base/data/home/apps/p~svasti-173418/internal-api:20170808t160537.403249868819304873/internal/cron/company_list.py", line 21, in run
company_repository.save(row,original_data_source, actual_data_source)
File "/base/data/home/apps/p~svasti-173418/internal-api:20170808t160537.403249868819304873/internal/repository/company_repository.py", line 13, in save
company.put()
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/model.py", line 3458, in _put
return self._put_async(**ctx_options).get_result()
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 383, in get_result
self.check_success()
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 378, in check_success
self.wait()
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/tasklets.py", line 362, in wait
if not ev.run1():
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/eventloop.py", line 268, in run1
delay = self.run0()
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/ext/ndb/eventloop.py", line 248, in run0
_logging_debug('rpc: %s.%s', rpc.service, rpc.method)
File "/base/data/home/runtimes/python27_experiment/python27_lib/versions/1/google/appengine/api/apiproxy_stub_map.py", line 453, in service
@property
DeadlineExceededError: The overall deadline for responding to the HTTP request was exceeded.
你的公司名单越来越大了吗 您要放置多少实体 尝试将它们保存为批处理,而不是按顺序保存在循环中。将
company.put()
从def save(dto、org\u ds、act\u dp):
中删除,然后使用ndb.put\u multi()
company_list = cron.rest_client.load(config, "companies", '')
if not company_list:
logging.info("Company list is empty")
return "Ok"
company_objs=[]
for row in company_list:
company_objs.append(company_repository.save(row,original_data_source,
actual_data_source))
# put 500 at a time
if len(company_objs) > 500:
ndb.put_multi(company_objs)
company_objs=[]
# put any remainders
if len(company_objs) > 0:
ndb.put_multi(company_objs)
你的公司名单越来越大了吗 您要放置多少实体 尝试将它们保存为批处理,而不是按顺序保存在循环中。将
company.put()
从def save(dto、org\u ds、act\u dp):
中删除,然后使用ndb.put\u multi()
company_list = cron.rest_client.load(config, "companies", '')
if not company_list:
logging.info("Company list is empty")
return "Ok"
company_objs=[]
for row in company_list:
company_objs.append(company_repository.save(row,original_data_source,
actual_data_source))
# put 500 at a time
if len(company_objs) > 500:
ndb.put_multi(company_objs)
company_objs=[]
# put any remainders
if len(company_objs) > 0:
ndb.put_multi(company_objs)
我的答案是基于Alex给出的答案,但是没有 我已将
put\u multi()
替换为put\u multi\u async()
通过将对put\u multi()
的调用替换为对其异步等价物put\u multi\u async()
的调用,应用程序可以立即执行其他操作,而不是阻塞put\u multi()
并添加了@ndb.toplevel
装饰器
此装饰程序告诉处理程序在其异步请求完成之前不要退出
如果您的数据越来越大,您可能需要更深入地研究。它可以用于每X批重新启动一次任务,以及剩余的未处理数据
@ndb.toplevel
def fetch_companies_list():
company_list = cron.rest_client.load(config, "companies", '')
if not company_list:
logging.info("Company list is empty")
return "Ok"
company_objs=[]
for row in company_list:
company_objs.append(company_repository.save(row,original_data_source,
actual_data_source))
# put 500 at a time
if len(company_objs) >= 500:
ndb.put_multi_async(company_objs)
company_objs=[]
# put any remainders
if len(company_objs) > 0:
ndb.put_multi_async(company_objs)
我的答案是基于Alex给出的答案,但是没有 我已将
put\u multi()
替换为put\u multi\u async()
通过将对put\u multi()
的调用替换为对其异步等价物put\u multi\u async()
的调用,应用程序可以立即执行其他操作,而不是阻塞put\u multi()
并添加了@ndb.toplevel
装饰器
此装饰程序告诉处理程序在其异步请求完成之前不要退出
如果您的数据越来越大,您可能需要更深入地研究。它可以用于每X批重新启动一次任务,以及剩余的未处理数据
@ndb.toplevel
def fetch_companies_list():
company_list = cron.rest_client.load(config, "companies", '')
if not company_list:
logging.info("Company list is empty")
return "Ok"
company_objs=[]
for row in company_list:
company_objs.append(company_repository.save(row,original_data_source,
actual_data_source))
# put 500 at a time
if len(company_objs) >= 500:
ndb.put_multi_async(company_objs)
company_objs=[]
# put any remainders
if len(company_objs) > 0:
ndb.put_multi_async(company_objs)
大约有6000只股票,这是一个相当大的数量,你可能会想要减少这件事。我修改了我的答案,一次输入500。根据我的经验,在1000多个对象上使用put_multi/get_multi时,ndb有时会挂起。它们大约有6000个库存,这是一个相当大的数量,这已经到了你可能想要减少这件事的程度。我修改了我的答案,一次输入500。根据我的经验,ndb有时会在1000多个主机上使用put_multi/get_multi时挂起objects@DanCornilescu为每个put生成任务队列如何?。由于我将加载6000条记录,因此也将有6000个任务队列可以工作-使用任务队列并不是那么简单,但它更灵活/可扩展。但是,如果每个公司要做的工作量很小,可能会显得有些过火,在这种情况下,处理每个任务的批次可能会更好。无论如何,在这种情况下需要注意的一点是,在任务创建时使用越来越长的
延迟
,以避免突然在应用程序中抛出一堆立即可执行的任务,这可能会导致启动许多动态实例,这可能会很昂贵。@Pythonist这与执行ndb.put\u multi()不一样吗
在整批6000件上?我想,ndb.put\u multi()
只是在多个实体上调用.put\u async()
的一个方便函数。@DanCornilescu为每个put生成任务队列怎么样?。由于我将加载6000条记录,因此也将有6000个任务队列可以工作-使用任务队列并不是那么简单,但它更灵活/可扩展。但是,如果每个公司要做的工作量很小,可能会显得有些过火,在这种情况下,处理每个任务的批次可能会更好。无论如何,在这种情况下需要注意的一点是,在任务创建时使用越来越长的延迟
,以避免突然在应用程序中抛出一堆立即可执行的任务,这可能会导致启动许多动态实例,这可能会很昂贵。@Pythonist这与执行ndb.put\u multi()不一样吗
在整批6000件上?我认为,ndb.put\u multi()
只是在多个实体上调用.put\u async()
的一个方便函数。