以下の例では、最大プールサイズとコアプールサイズを1に設定していますが、メッセージは処理されていません。デバッグログを有効にすると、SQSからプルされているメッセージを確認できますが、処理/削除されていないようです。ただし、コアと最大プールのサイズを2に増やすと、メッセージが処理されているように見えます。
[〜#〜]編集[〜#〜]
Springは、キューからデータを読み取るレシーバーにスレッドを割り当てている可能性があるため、メッセージを処理しているリスナーにスレッドを割り当てることができないと思います。 corepoolsizeを2に増やすと、メッセージがキューから読み取られているのがわかりました。別のリスナーを追加したとき(デッドレターキュー用)、同じ問題が発生しました-メッセージが処理されていなかったため、2つのスレッドでは不十分でした。 corepoolsizeを3に増やすと、メッセージの処理が開始されました。この場合、キューからメッセージを読み取るために1つのスレッドが割り当てられ、2つのリスナーにそれぞれ1つのスレッドが割り当てられたと想定します。
@Configuration
public class SqsListenerConfiguration {
@Bean
@ConfigurationProperties(prefix = "aws.configuration")
public ClientConfiguration clientConfiguration() {
return new ClientConfiguration();
}
@Bean
@Primary
public AWSCredentialsProvider awsCredentialsProvider() {
ProfileCredentialsProvider credentialsProvider = new ProfileCredentialsProvider("credential");
try {
credentialsProvider.getCredentials();
System.out.println(credentialsProvider.getCredentials().getAWSAccessKeyId());
System.out.println(credentialsProvider.getCredentials().getAWSSecretKey());
} catch (Exception e) {
throw new AmazonClientException(
"Cannot load the credentials from the credential profiles file. " +
"Please make sure that your credentials file is at the correct " +
"location (~/.aws/credentials), and is in valid format.",
e);
}
return credentialsProvider;
}
@Bean
@Primary
public AmazonSQSAsync amazonSQSAsync() {
return AmazonSQSAsyncClientBuilder.standard().
withCredentials(awsCredentialsProvider()).
withClientConfiguration(clientConfiguration()).
build();
}
@Bean
@ConfigurationProperties(prefix = "aws.queue")
public SimpleMessageListenerContainer simpleMessageListenerContainer(AmazonSQSAsync amazonSQSAsync) {
SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer();
simpleMessageListenerContainer.setAmazonSqs(amazonSQSAsync);
simpleMessageListenerContainer.setMessageHandler(queueMessageHandler());
simpleMessageListenerContainer.setMaxNumberOfMessages(10);
simpleMessageListenerContainer.setTaskExecutor(threadPoolTaskExecutor());
return simpleMessageListenerContainer;
}
@Bean
public QueueMessageHandler queueMessageHandler() {
QueueMessageHandlerFactory queueMessageHandlerFactory = new QueueMessageHandlerFactory();
queueMessageHandlerFactory.setAmazonSqs(amazonSQSAsync());
QueueMessageHandler queueMessageHandler = queueMessageHandlerFactory.createQueueMessageHandler();
return queueMessageHandler;
}
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setMaxPoolSize(1);
executor.setThreadNamePrefix("oaoQueueExecutor");
executor.initialize();
return executor;
}
@Bean
public QueueMessagingTemplate messagingTemplate(@Autowired AmazonSQSAsync amazonSQSAsync) {
return new QueueMessagingTemplate(amazonSQSAsync);
}
}
リスナー構成
@SqsListener(value = "${oao.sqs.url}", deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS)
public void onMessage(String serviceData, @Header("MessageId") String messageId, @Header("ApproximateFirstReceiveTimestamp") String approximateFirstReceiveTimestamp) {
System.out.println(" Data = " + serviceData + " MessageId = " + messageId);
repository.execute(serviceData);
}
corePoolSize
とmaximumPoolSize
を同じに設定すると、fixed-size thread pool
が作成されます。ルールの非常に良い説明が文書化されています ここ
maxPoolSize
を設定すると、タスクを暗黙的にドロップできます。ただし、デフォルトのキュー容量はInteger.MAX_VALUE
であり、実用的な目的では無限大です。
注意すべき点は、ThreadPoolTaskExecutor
が下にThreadPoolExecutor
を使用していることです。これは、 docs で説明されているように、キューイングに対してやや変わったアプローチを採用しています。
corePoolSize
以上のスレッドが実行されている場合、エグゼキュータは常に、新しいスレッドを追加するのではなく、リクエストをキューに入れることを好みます。
つまり、maxPoolSize
はキューがいっぱいの場合にのみ関係します。そうでない場合、スレッドの数がcorePoolSize
を超えることはありません。例として、完了しないタスクをスレッドプールに送信すると、次のようになります。
corePoolSize
送信は、それぞれ新しいスレッドを開始します。maxPoolSize
までの新しいスレッドを開始します。キューイング-読む docs
任意のBlockingQueue
を使用して、送信されたタスクを転送および保持できます。このキューの使用は、プールのサイズ設定と相互作用します。
Unbounded queues
。無制限のキュー(たとえば、事前定義された容量のないLinkedBlockingQueue
)を使用すると、すべてのcorePoolSizeスレッドがビジーの場合に新しいタスクがキューに入れられます。したがって、作成されるスレッドはcorePoolSize
以下です。 (したがって、maximumPoolSize
の値は効果がありません。)
corePoolSize
未満の場合は、新しいスレッドを作成して新しいタスクを実行します。corePoolSize
と等しい(または多い)場合は、タスクをキューに入れます。maxPoolSize
未満の場合は、タスクを実行するための新しいスレッドを作成します。maxPoolSize
以上の場合、タスクを拒否します。