LoginSignup
4
1

More than 3 years have passed since last update.

S3からオブジェクトを取得したときは解放を忘れずに!

Posted at

環境

  • Java8
  • AWS SDK for Java 1.11

現象

S3からオブジェクト取得時に、以下のようなエラーが発生した。

org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool

問題のコード

public InputStream getFile(String bucketName,String prefix){
  try{
    GetObjectRequest request = new GetObjectRequest(bucketName, prefix);
    S3Object object = s3client.getObject(request); // s3clientはシングルトンインスタンス変数として生成済み
    return object.getObjectContent();
  } catch(AmazonServiceException e){
    throw e;
  }
}

原因

S3Objectを取得した際に、解放処理が行われていないため。
S3内部でHTTPコネクションプールサイズを持っており、デフォルトで50となっている。
これを越えると上記のエラーが発生。

解決方法

その1 S3クライアントのラッパークラスなどで行う場合

public InputStream getFile(String bucketName,String prefix){
  GetObjectRequest request = new GetObjectRequest(bucketName, prefix);
  try(S3Object object = s3client.getObject(request)){
    // メモリに展開。ここでS3Objectの参照をなくす
    byte[] file = IOUtils.toByteArray(object.getObjectContent());
    // byte[]からInputStreamにして返却
    return new ByteArrayInputStream(file);
  } catch(AmazonServiceException e){
    throw e;
  } catch(IOException e){
    throw new RuntimeException(e);
  }
}

一時的にメモリに展開しているので注意が必要。
解放処理を行う関係で、InputStreamをそのまま返却できない。

その2 呼び出し側で解放する場合

public static main(String[] args){
  try(S3Object object = getFile("hoge","fuga")){
    処理
  }catch (IOException e) {
    throw new RuntimeException(e);
  }
}

public S3Object getFile(String bucketName,String prefix){
  try{
    GetObjectRequest request = new GetObjectRequest(bucketName, prefix);
    return s3client.getObject(request);
  } catch(AmazonServiceException e){
    throw e;
  }
}

解放処理を呼び出しごとに行う必要があるが、InputStreamを扱える。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1