Spring boot/spring-cloud-aws SQS 在部署到 AWS/EC2 环境时无法轮询消息

Spring boot/spring-cloud-aws SQS failing to poll messages when deployed to AWS/EC2 environment

Spring 启动应用程序工作正常运行 在本地连接到沙箱 S3 和沙箱 SQS,使用 DefaultAWSCredentialsProviderChain 并设置为系统 属性。

当应用程序部署到 EC2 环境并使用 ProfileCredentials 时,我在 CloudWatch 中收到连续的以下错误流:

{
    "Host": "<myhost>",
    "Date": "2016-12-20T21:52:56,777",
    "Thread": "simpleMessageListenerContainer-1",
    "Level": "WARN ",
    "Logger": "org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer",
    "Msg": "An Exception occurred while polling queue 'my-queue-name'. The failing operation will be retried in 10000 milliseconds",
    "Identifiers": {
        "Jvm-Instance": "",
        "App-Name": "my-app",
        "Correlation-Id": "ca9a556e-2fbc-3g49-9fb8-0e9213bb79bc",
        "Session-Id": "",
        "Thread-Group": "main",
        "Thread-Id": "32",
        "Version": ""
    }
}
java.lang.NullPointerException
at org.springframework.cloud.aws.messaging.listener.SimpleMessageListenerContainer$AsynchronousMessageListener.run(SimpleMessageListenerContainer.java:255) [spring-cloud-aws-messaging-1.1.1.RELEASE.jar:1.1.1.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_91]

问题归结为 SimpleMessageListenerContainer.java:255 :

ReceiveMessageResult receiveMessageResult = getAmazonSqs().receiveMessage(this.queueAttributes.getReceiveMessageRequest());

this.queueAttributes 为空。

我已经尝试了所有方法,包括 @EnableContextCredentials(instanceProfile=true),以设置 cloud.aws.credentials.instanceProfile=true,同时确保 access & secretKey 为空。 SQS 队列肯定存在,我已经通过 EC2 实例本身的 aws cli 验证了配置文件凭据存在并且有效。

此外,在 AWS 环境中,该应用程序还使用 S3 客户端为存储桶生成唯一密钥,这一切都有效。只有当应用程序尝试从似乎失败的 SQS 中轮询消息时才会出现这种情况。

我正在这样处理消息:

@SqsListener("${aws.sqs.queue.name}")
public void receive(S3EventNotification s3EventNotificationRecord) {

更多配置:

@Bean
   public AWSCredentialsProvider awsCredentialsProvider(
           @Value("${aws.credentials.accessKey}") String accessKey,
           @Value("${aws.credentials.secretKey}") String secretKey,
           JasyptPropertyDecryptor propertyDecryptor) {
       if (!Strings.isNullOrEmpty(accessKey) || !Strings.isNullOrEmpty(secretKey)) {
           Preconditions.checkState(
                   !Strings.isNullOrEmpty(accessKey) && !Strings.isNullOrEmpty(secretKey),
                   "Error in accessKey/secretKey config. Either both must be provided, or neither.");
           System.setProperty("aws.accessKeyId", propertyDecryptor.decrypt(accessKey));
           System.setProperty("aws.secretKey", propertyDecryptor.decrypt(secretKey));
       }
       return DefaultAWSCredentialsProviderChain.getInstance();
   }

   @Bean
   public S3Client s3Client(
           AWSCredentialsProvider awsCredentialsProvider,
           @Value("${aws.s3.region.name}") String regionName,
           @Value("${aws.s3.bucket.name}") String bucketName) {
       return new S3Client(awsCredentialsProvider, regionName, bucketName);
   }

   @Bean
   public QueueMessageHandlerFactory queueMessageHandlerFactory() {

       MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
       messageConverter.setStrictContentTypeMatch(false);

       QueueMessageHandlerFactory factory = new QueueMessageHandlerFactory();
       factory.setArgumentResolvers(
           Collections.<HandlerMethodArgumentResolver>singletonList(
               new PayloadArgumentResolver(messageConverter)));

       return factory;
   }

我注意到的另一件事是,在应用程序启动时,会调用 ContextConfigurationUtils.registerCredentialsProvider,除非您在 app.properties 中将 cloud.aws.credentials.profileName= 指定为空,否则此 class 将将 ProfileCredentialsProvider 添加到 awsCredentialsProviders 的列表中。我认为这可能有问题,因为我没有以这种方式在 EC2 实例上提供凭证,而是应该使用 InstanceProfileCredentialsProvider。此更改无效。

原来问题是我在 AWS 中使用的服务(例如 SQS)对它们具有适当的访问权限,但 IAM 配置文件本身缺乏权限,甚至无法尝试应用程序需要进行的服务操作。