为什么有时我会使用SQS客户端收到密钥错误

时间:2018-10-06 01:43:59

标签: python amazon-web-services boto3 amazon-sqs

我正在使用boto3 SQS客户端从AWS SQS FIFO队列接收消息。

def consume_msgs():
    sqs = None
    try:
        sqs = boto3.client('sqs',
                       region_name=S3_BUCKET_REGION,
                       aws_access_key_id=AWS_ACCESS_KEY_ID,
                       aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
    except Exception:
        logger.warning('SQS client error {}'.format(sys.exc_info()[0]))
        logger.error(traceback.format_exc())

  ### more code to process message

使用upstart在EC2上将应用程序设置为服务。大部分时间都可以正常工作。但是有时候,当我在代码更改后重新启动服务时,应用程序会退出并显示以下错误

2018-10-06 01:29:38,654 WARNING SQS client error <class 'KeyError'>
2018-10-06 01:29:38,658 WARNING SQS client error <class 'KeyError'>
2018-10-06 01:29:38,663 ERROR Traceback (most recent call last):
  File "/home/ec2-user/aae_client/app/run.py", line 194, in consume_msgs
    aws_secret_access_key=AWS_SECRET_ACCESS_KEY)
  File "/home/ec2-user/aae_client/env/lib64/python3.6/dist-packages/boto3/__init__.py", line 83, in client
    return _get_default_session().client(*args, **kwargs)
  File "/home/ec2-user/aae_client/env/lib64/python3.6/dist-packages/boto3/session.py", line 263, in client
    aws_session_token=aws_session_token, config=config)
  File "/home/ec2-user/aae_client/env/lib64/python3.6/dist-packages/botocore/session.py", line 851, in create_client
    endpoint_resolver = self.get_component('endpoint_resolver')
  File "/home/ec2-user/aae_client/env/lib64/python3.6/dist-packages/botocore/session.py", line 726, in get_component
    return self._components.get_component(name)
  File "/home/ec2-user/aae_client/env/lib64/python3.6/dist-packages/botocore/session.py", line 926, in get_component
    del self._deferred[name]
KeyError: 'endpoint_resolver'

重新启动服务通常可以解决该问题。每次我重新启动服务时都不会发生。令人困惑的是KeyError警告导致实际错误回溯。 KeyError到底指的是什么?不能为AWS_SECRET_ACCESS_KEY,因为此密钥从不更改,并且在大多数情况下都可以正常工作。这个问题是随机发生的,而且时有发生。因此很难调试。而且我不明白该错误如何逃脱了try..except

编辑

基于注释,这似乎与多线程有关。 consume_msg实际上是由多个线程运行的 def process_msgs():

for i in range(NUM_WORKERS):
    t = threading.Thread(target=consume_msgs, name='worker-%s' % i)
    t.setDaemon(True)
    t.start()
while True:
    time.sleep(MAIN_PROCESS_SLEEP_INTERVAL)

3 个答案:

答案 0 :(得分:2)

也许我误解了其他一些答案,但是在多线程执行的情况下,我认为拥有一个boto3客户端对象并将其传递给其他功能不会在这些功能在单独的线程中执行的情况下起作用。我在调用boto3客户端服务时遇到了偶发的endpoint_resolver错误,并且按照documentation中的示例以及关于boto3 GitHub问题(例如#1246和{{ 3}},并在每个线程中创建一个单独的会话对象。在我的情况下,这意味着我的代码发生了几乎微不足道的更改,从

开始
client = boto3.client(variant, region_name = creds['region_name'],
                      aws_access_key_id = ...,
                      aws_secret_access_key = ...)

session = boto3.session.Session()
client = session.client(variant, region_name = creds['region_name'],
                        aws_access_key_id = ...,
                        aws_secret_access_key = ...)
在单独线程中执行的函数中的

。我对consume_msgs()的OP代码的理解是,可以进行类似的更改,并且可以消除偶发的endpoint_resolver错误。

答案 1 :(得分:1)

github issue建议您一次在顶级(而不是在函数中)设置sqs客户端:

sqs = boto3.client('sqs',
                   region_name=S3_BUCKET_REGION,
                   aws_access_key_id=AWS_ACCESS_KEY_ID,
                   aws_secret_access_key=AWS_SECRET_ACCESS_KEY)


def consume_msgs():
    # code to process message

答案 2 :(得分:0)

为S3创建客户端时出现此错误,但AFAIK是同一个问题。 创建客户端的过程中使用了非线程安全的代码:

        if name in self._deferred:
            factory = self._deferred[name]
            self._components[name] = factory()
            # Only delete the component from the deferred dict after
            # successfully creating the object from the factory as well as
            # injecting the instantiated value into the _components dict.
            del self._deferred[name]

(来自get_component方法中的botocore / session.py-这是在尝试删除由其他线程删除的键时引发KeyError的代码)

锁定客户端创建可以为我解决(如https://github.com/boto/boto3/pull/806中的建议)