S3 java v1 => v2: putObject работает только при отладке — Исключение SdkClientException: не удается выполнить HTTP-запрос: время ожидания чтения истекло

#java #amazon-web-services #amazon-s3 #localstack

#java #amazon-web-services #amazon-s3 #localstack

Вопрос:

Я хочу перейти с S3 java v1 на v2, и теперь по какой-то причине небольшой интеграционный тест начал завершаться неудачей. При отладке и пошаговом выполнении он работает. Вот код (я получил localstackhttps://github.com/localstack/localstack запущен экземпляр):

 @RunWith(SpringRunner::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class S3ConfigurationTest {

@Autowired
@Qualifier("historicalDataS3")
lateinit var s3: S3Client

@Test
fun `can write and read object on s3`() {
    var bucket = s3.listBuckets().buckets().first()

    val uid = UUID.randomUUID().toString()

    s3.putObject(
        PutObjectRequest.builder().bucket(bucket.name()).key(uid)
            .build(),
        RequestBody.fromString("test test test"))

    val read =
        String(s3.getObject(GetObjectRequest.builder().bucket(bucket.name()).key(uid).build()).readBytes())

    Assertions.assertThat(read).isEqualTo("test test test")
}
  

и это исключение, коренящееся в строке putObject:

software.amazon.awssdk.core.exception.Исключение SdkClientException: не удается выполнить HTTP-запрос: время ожидания чтения истекло

 at software.amazon.awssdk.core.exception.SdkClientException$BuilderImpl.build(SdkClientException.java:97)
at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage$RetryExecutor.handleThrownException(RetryableStage.java:136)
at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage$RetryExecutor.execute(RetryableStage.java:94)
at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage.execute(RetryableStage.java:62)
at software.amazon.awssdk.core.internal.http.pipeline.stages.RetryableStage.execute(RetryableStage.java:42)
at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
at software.amazon.awssdk.core.internal.http.StreamManagingStage.execute(StreamManagingStage.java:51)
at software.amazon.awssdk.core.internal.http.StreamManagingStage.execute(StreamManagingStage.java:33)
at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallTimeoutTrackingStage.executeWithTimer(ApiCallTimeoutTrackingStage.java:79)
at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallTimeoutTrackingStage.execute(ApiCallTimeoutTrackingStage.java:60)
at software.amazon.awssdk.core.internal.http.pipeline.stages.ApiCallTimeoutTrackingStage.execute(ApiCallTimeoutTrackingStage.java:42)
at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
at software.amazon.awssdk.core.internal.http.pipeline.RequestPipelineBuilder$ComposingRequestPipelineStage.execute(RequestPipelineBuilder.java:206)
at software.amazon.awssdk.core.internal.http.pipeline.stages.ExecutionFailureExceptionReportingStage.execute(ExecutionFailureExceptionReportingStage.java:37)
at software.amazon.awssdk.core.internal.http.pipeline.stages.ExecutionFailureExceptionReportingStage.execute(ExecutionFailureExceptionReportingStage.java:26)
at software.amazon.awssdk.core.internal.http.AmazonSyncHttpClient$RequestExecutionBuilderImpl.execute(AmazonSyncHttpClient.java:240)
at software.amazon.awssdk.core.client.handler.BaseSyncClientHandler.invoke(BaseSyncClientHandler.java:96)
at software.amazon.awssdk.core.client.handler.BaseSyncClientHandler.execute(BaseSyncClientHandler.java:120)
at software.amazon.awssdk.core.client.handler.BaseSyncClientHandler.execute(BaseSyncClientHandler.java:73)
at software.amazon.awssdk.core.client.handler.SdkSyncClientHandler.execute(SdkSyncClientHandler.java:44)
at software.amazon.awssdk.awscore.client.handler.AwsSyncClientHandler.execute(AwsSyncClientHandler.java:55)
at software.amazon.awssdk.services.s3.DefaultS3Client.putObject(DefaultS3Client.java:3053)
  

Что здесь происходит? Что касается примеров, это должно просто работать https://github.com/awsdocs/aws-doc-sdk-examples/blob/master/javav2/example_code/s3/src/main/java/com/example/s3/S3ObjectOperations.java

Ответ №1:

Основная причина в том, что ваш код выполняется быстрее, чем то, что AWS может передавать между его внутренними компонентами.

Вам нужно замедлить выполнение вашего кода или запустить waiter, который выполняет цикл и ждет, пока s3Client.doesBucketExistV2(BucketName) не вернет true.