前提
業務でこんな処理を実装する気がするので、簡単に予習してみます。
今回は動くか検証のみなので、ローカルで起動したJavaアプリケーション(Spring Boot)からSQSにメッセージを送信してみます。
本当はlambdaからrdsへ登録・更新する処理を実装したかったのですが、それはまた別の機会に。(なのでSQSやlambdaの名前がmergeXXXXみたいになってます。)
環境
- macOS: 12.6
- IntelliJ IDEA: 2022.2.3 (Community Edition)
- Gradle: 7.5
- Java: temurin 17.0.3
手順
プロジェクトの作成
spring initializrでプロジェクト作成
https://start.spring.io/でプロジェクトの雛形を作成します。
以下の画像のような構成にしています。
GENERATEボタンを押してダウンロードしてきます。それをIDEツールで開きます。
build.gradleの設定
com.amazonaws:aws-java-sdk-bom
とcom.amazonaws:aws-java-sdk-sqs
を設定します。
この時点ではどちらも1.12.320が最新でした。
plugins {
id 'org.springframework.boot' version '2.7.5-SNAPSHOT'
id 'io.spring.dependency-management' version '1.0.14.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.amazonaws:aws-java-sdk-bom:1.12.320'
implementation 'com.amazonaws:aws-java-sdk-sqs:1.12.320'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
tasks.named('test') {
useJUnitPlatform()
}
AWS側の設定
IAMユーザーの作成
事前にJavaからアクセスするためのIAMユーザーを作成し、アクセスキーとシークレットキーをダウンロードしておきます。
そのIAMユーザーを使用してコンロールでSQS等を作成します。
SQSのキューを作成
lambdaを作成
IAMロールを作成する
lambdaからSQSを読み取りするのでIAMロールを作成します。
こちらを参考にさせていただきました。
https://www.stsd.co.jp/dev-blog/send_and_receive_amazon_sqs_messages_from_java.html#:~:text=SQS%E3%81%AB%E3%81%AFJava%E3%81%A7,%E3%82%A2%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E3%80%8D%E3%82%92%E9%81%B8%E6%8A%9E%E3%81%97%E3%81%BE%E3%81%99%E3%80%82
- ロール名:for-sqs
- ポリシー名:sqs-policy
- ポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"sqs:DeleteMessage",
"sqs:ReceiveMessage",
"sqs:GetQueueAttributes"
],
"Resource": "*"
}
]
}
またロールにAWSLambdaBasicExecutionRoleをアタッチしておくと、CloudWatchログにログを書き込めます。
lambdaにIAMロールの設定
コンロールのlambdaのページを開き、設定タブ > アクセス権限 > 実行ロール > 編集ボタンで設定します。
SQSでLambdaトリガーを設定
SQSのページで作成したキューを選択し、Lambdaトリガータブからlambdaを設定します。
これでaws側の設定は完了です。
実装
SqsClient
こちらを参考にしました。
https://docs.aws.amazon.com/ja_jp/sdk-for-java/v1/developer-guide/examples-sqs-messages.html
package com.example.lambdasqssample.aws;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.sqs.AmazonSQS;
import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
import com.amazonaws.services.sqs.model.AmazonSQSException;
import com.amazonaws.services.sqs.model.CreateQueueRequest;
import com.amazonaws.services.sqs.model.SendMessageRequest;
import org.springframework.stereotype.Component;
@Component
public class SqsClient {
private static final String QUEUE_NAME = "merge-data-sqs";
public String getQueueUrl() {
var sqs = getSqs();
var create_request = new CreateQueueRequest(QUEUE_NAME)
.addAttributesEntry("DelaySeconds", "60")
.addAttributesEntry("MessageRetentionPeriod", "86400");
try {
sqs.createQueue(create_request);
} catch (AmazonSQSException e) {
if (!e.getErrorCode().equals("QueueAlreadyExists")) {
throw e;
}
}
return sqs.getQueueUrl(QUEUE_NAME).getQueueUrl();
}
public void sendMessage(String queueUrl) {
var sqs = getSqs();
var send_msg_request = new SendMessageRequest()
.withQueueUrl(queueUrl)
.withMessageBody("hello world")
.withDelaySeconds(5);
sqs.sendMessage(send_msg_request);
}
private AmazonSQS getSqs() {
return AmazonSQSClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(Credentials.get()))
.withRegion(Regions.AP_NORTHEAST_1.getName())
.build();
}
}
package com.example.lambdasqssample.aws;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class Credentials {
private static String ACCESS_KEY;
private static String SECRET_KEY;
@Value("${aws.access-key}")
public void setAccessKey(String accessKey) {
this.ACCESS_KEY = accessKey;
}
@Value("${aws.secret-key}")
public void setSecretKey(String secretKey) {
this.SECRET_KEY = secretKey;
}
public static AWSCredentials get() {
return new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY);
}
}
ACCESS_KEYとSECRET_KEYはapplication.ymlで設定しておきます。
実行クラス
QueueのUrlを受け取り、メッセージを送信します。
package com.example.lambdasqssample.Controller;
import com.example.lambdasqssample.aws.SqsClient;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1/sample")
@RequiredArgsConstructor
public class SampleController {
private final SqsClient sqsClient;
@GetMapping("/result")
public boolean getResult() {
var queue = sqsClient.getQueueUrl();
sqsClient.sendMessage(queue);
return true;
}
}
これで実装は完了です。
実行
アプリケーションをビルド・実行します。
今回はpostmanを使用してhttp://localhost:8080/api/v1/sample/result
にGETします。
CloudWatchログを見ると、アクセスするたびに実行されていることがわかります。
さいごに
まだlambdaで具体的な処理を実行していないですが、とりあえず動くことを確認できた第一歩でした。