環境
- 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
を扱える。