我已经阅读了其他问题和答案,但仍然无法弄清我在做什么错。
我正在尝试使用ES的asyncio实现(https://github.com/elastic/elasticsearch-py-async)在Python 3.6中创建Elasticsearch 6.x生产者,并且在它工作时(记录已成功推送到ES中),我得到了{{1} }和Task Exception was never retried
错误。我认为它们都是相同的问题造成的,而一个可能是导致另一个的原因?
我正在使用以下模块:
Task got bad yield: 200
下面是我的代码:
python 3.6
elasticsearch=6.3.1
elasticsearch-async=6.2.0
boto3=1.9.118
以下是我每次致电import json
import boto3
import logging
import os
import gzip
import asyncio
from elasticsearch import RequestsHttpConnection
from elasticsearch_async import AsyncElasticsearch
from assume_role_aws4auth import AssumeRoleAWS4Auth
import time
logger = logging.getLogger()
logger.setLevel(logging.INFO)
# Operating constants
MAX_RECORDS_IN_BATCH = 500
MAX_BATCH_SIZE = 10000000
# boto3 clients
credentials = boto3.Session().get_credentials()
awsauth = AssumeRoleAWS4Auth(credentials, 'us-east-1', 'es')
cloudwatch_client = boto3.client('cloudwatch')
s3_resource = boto3.resource('s3')
event_loop = asyncio.get_event_loop()
es_client = AsyncElasticsearch(hosts=['https://ES_HOST'], http_compress=True, http_auth=awsauth, use_ssl=True,
verify_certs=True, connection_class=RequestsHttpConnection, loop=event_loop)
def lambda_handler(filename, context):
event_loop.run_until_complete(process(filename))
pending = asyncio.Task.all_tasks()
event_loop.run_until_complete(asyncio.gather(*pending))
async def process(filename: str):
for action_chunk in read_chunk(filename, MAX_BATCH_SIZE, MAX_RECORDS_IN_BATCH):
try:
resp = asyncio.ensure_future(es_client.bulk(body=action_chunk, index='index', doc_type='type', _source=False))
await asyncio.sleep(.1)
except Exception as ex:
logger.error(ex)
def read_chunk(file_path: str, max_batch_size: int, max_records: int):
actions: str = ''
actions_size: int = 0
num_actions: int = 0
with gzip.open(file_path, 'rt') as f:
for line in f:
request = json.dumps(dict({'index': dict({})})) + '\n' + line + '\n'
request_size = len(request.encode('utf-8'))
# Check to see if this record will put us over the limits
if (actions_size + request_size) > max_batch_size or num_actions == max_records:
yield actions
actions = ''
num_actions = 0
actions_size = 0
# Add the record
actions += request
num_actions += 1
actions_size += request_size
if actions != '':
yield actions
if __name__ == '__main__':
lambda_handler('/path/to/file', None)
时遇到的错误:
es_client.bulk
有人可以告诉我我在做什么错吗?另外,如果有什么我可以做的更好/更有效的事情,我很想听听。我想使用Helpers软件包,但没有异步实现。
答案 0 :(得分:1)
我不确定是否是问题所在,但是这可能会发生。
您可以在process()
协程中创建多个任务,但不要存储对它们的引用。这可能会导致问题:在显式检索它们的结果之前,有些任务是garbage collected。如果发生这种情况,asyncio
warns请您注意情况。
要解决此问题,您应该存储所有创建的任务,并确保等待所有任务:
tasks = []
# ...
async def process(filename: str):
# ...
task = asyncio.ensure_future(...)
tasks.append(task)
# ...
def lambda_handler(filename, context):
# ...
event_loop.run_until_complete(asyncio.gather(*tasks ))
如果我的猜测是正确的,您可能会看到RuntimeError('Task got bad yield: 200',)
处出现了lambda_handler
。您可以检索所有异常,而无需引发将return_exceptions=True
参数传递给asyncio.gather的异常。这样,您可以避免发出警告(但不能避免这些异常首先发生的根本原因)。
很抱歉,除了这里没有其他帮助。
更新:
我更改了原始版本的答案修正错误。