Java SqsAckSink使Akka流永远挂起,导致图形重新启动
我正在尝试使用SQS源代码和Localstack实现一个简单的工作流。 如果我添加Java SqsAckSink使Akka流永远挂起,导致图形重新启动,java,akka,akka-stream,localstack,Java,Akka,Akka Stream,Localstack,我正在尝试使用SQS源代码和Localstack实现一个简单的工作流。 如果我添加SqsAckSink,它就不能工作,它也不能与SqsAckFlow一起工作。但是如果我删除SqsAckSink并只使用Sink.seq(),那么测试就通过了。拥有SqsAckSink或SqsAckFlow会使测试永远挂起。我还在测试中启用了debug,看到相同的错误一次又一次地重复,使图形重新启动,但这对我来说没有多大意义。我在下面的代码片段之后发布错误消息 代码是: public class Defaul
SqsAckSink
,它就不能工作,它也不能与SqsAckFlow
一起工作。但是如果我删除SqsAckSink
并只使用Sink.seq()
,那么测试就通过了。拥有SqsAckSink
或SqsAckFlow
会使测试永远挂起。我还在测试中启用了debug,看到相同的错误一次又一次地重复,使图形重新启动,但这对我来说没有多大意义。我在下面的代码片段之后发布错误消息
代码是:
public class DefaultWorkflow implements Workflow {
private Function<Throwable, Supervision.Directive> errorStrategy;
private final ActorSystem actorSystem;
private FlowMonitor<ProvisioningResult> workflowMonitor;
private final String queueUrl;
private final SqsAsyncClient asyncClient;
@Inject
public DefaultWorkflow(ActorSystem actorSystem, String queueUrl) {
this.errorStrategy = exc -> (Supervision.Directive) Supervision.resume();
this.actorSystem = actorSystem;
this.queueUrl = queueUrl;
asyncClient =
SqsAsyncClient.builder()
.region(Region.of(Localstack.getDefaultRegion()))
.httpClient(AkkaHttpClient.builder().withActorSystem(actorSystem).build())
.endpointOverride(new URI(queueUrl))
.build();
doWork();
}
private Flow<Message, ProvisioningResult, NotUsed> buildFlow() {
return Flow.of(Message.class)
.via(Flow.of(Message.class).map(m -> ProvisioningResult.builder().body(m.body()).build()));
}
@Override
public Source<ProvisioningResult, FlowMonitor<ProvisioningResult>> getSource() {
Source<Message, NotUsed> sqsSource =
RestartSource.onFailuresWithBackoff(
Duration.ofSeconds(1), Duration.ofSeconds(2), 0.1, this::createSQSSource);
return sqsSource
.via(buildFlow())
.withAttributes(ActorAttributes.withSupervisionStrategy(errorStrategy))
.monitorMat(Keep.right());
}
private Source<Message, NotUsed> createSQSSource() {
SqsSourceSettings sqsSourceSettings = SqsSourceSettings.create().withMaxBatchSize(1);
return SqsSource.create(queueUrl, sqsSourceSettings, asyncClient);
}
@Override
public FlowMonitor<ProvisioningResult> getWorkflowMonitor() {
return this.workflowMonitor;
}
private void doWork() {
Pair<FlowMonitor<ProvisioningResult>, CompletionStage<Done>> run =
getSource()
.toMat(SqsAckSink.create(queueUrl, SqsAckSettings.create(), asyncClient), Keep.both())
.run(actorSystem);
workflowMonitor = run.first();
}
}
public类DefaultWorkflow实现工作流{
私人职能战略;
私有最终ActorSystem ActorSystem;
专用流量监视器workflowMonitor;
私有最终字符串队列URL;
专用最终SqsAsyncClient异步客户端;
@注入
公共默认工作流(ActorSystem ActorSystem,字符串queueUrl){
this.errorStrategy=exc->(Supervision.Directive)Supervision.resume();
this.actorSystem=actorSystem;
this.queueUrl=queueUrl;
异步客户端=
SqsAsyncClient.builder()
.region(region.of(Localstack.getDefaultRegion()))
.httpClient(AkkaHttpClient.builder().withActorSystem(actorSystem.build())
.endpointOverride(新URI(queueUrl))
.build();
销钉();
}
私有流buildFlow(){
返回流.of(Message.class)
.via(Flow.of(Message.class).map(m->ProvisioningResult.builder().body(m.body()).build());
}
@凌驾
公共源getSource(){
源SQS源=
RestartSource.onFailuresWithBackoff(
持续时间(1),持续时间(2),0.1,this::createSQSSource);
返回sqsSource
.via(buildFlow())
.withAttributes(ActorAttributes.withSupervisionStrategy(errorStrategy))
.monitorat(Keep.right());
}
私有源createSQSSource(){
SqsSourceSettings SqsSourceSettings=SqsSourceSettings.create(),带MaxBatchSize(1);
返回SqsSource.create(queueUrl、sqsSourceSettings、asyncClient);
}
@凌驾
公共流监视器getWorkflowMonitor(){
返回此.workflowMonitor;
}
私房{
双人跑=
getSource()
.toMat(SqsAckSink.create(queueUrl、SqsAckSettings.create()、asyncClient)、Keep.both())
.运行(actorSystem);
workflowMonitor=run.first();
}
}
测试如下所示:
@Test
public void getSource_givenMessage_shouldProduceResult()
throws InterruptedException, ExecutionException, TimeoutException, URISyntaxException {
String sqsName = "sqs2";
String messageBody = "someMessage";
String sqsUrl = initSQS(sqsName);
generateSourceData(sqsUrl, messageBody);
this.defaultWorkflow = new DefaultWorkflow(this.actorSystem, sqsUrl);
Source<ProvisioningResult, FlowMonitor<ProvisioningResult>> source =
defaultWorkflow.getSource();
final CompletionStage<List<ProvisioningResult>> future =
source.take(1).runWith(Sink.seq(), materializer);
final List<ProvisioningResult> result = future.toCompletableFuture().join();
assertEquals(1, result.size());
assertEquals(result.get(0).getBody(), messageBody);
}
public void generateSourceData(String queueUrl, String messageBody) {
client
.sendMessage(
SendMessageRequest.builder().queueUrl(queueUrl).messageBody(messageBody).build())
.join();
}
private void initClient() throws URISyntaxException {
System.setProperty(SdkSystemSetting.CBOR_ENABLED.property(), "false");
AwsCredentials credentials = AwsBasicCredentials.create("somekey", "somevalue");
StaticCredentialsProvider provider = StaticCredentialsProvider.create(credentials);
client =
SqsAsyncClient.builder()
.region(Region.of(Localstack.getDefaultRegion()))
.httpClient(AkkaHttpClient.builder().withActorSystem(ActorSystem.create()).build())
.credentialsProvider(provider)
.endpointOverride(new URI(Localstack.INSTANCE.getEndpointSQS()))
.build();
}
protected String initSQS(String queueName) throws URISyntaxException {
initClient();
client
.createQueue(CreateQueueRequest.builder().queueName(queueName).build())
.join()
.queueUrl();
GetQueueUrlResponse response = client.getQueueUrl(GetQueueUrlRequest.builder().queueName(queueName).build()).join();
System.out.println("Using queue " + response);
log.info("Using queue {}", response);
return response.queueUrl();
}
@测试
public void getSource\u givenMessage\u shouldProduceResult()
抛出InterruptedException、ExecutionException、TimeoutException、URISyntaxException{
字符串sqsName=“sqs2”;
字符串messageBody=“someMessage”;
字符串sqsUrl=initSQS(sqsName);
generateSourceData(sqsUrl,messageBody);
this.defaultWorkflow=新的defaultWorkflow(this.actorSystem,sqsUrl);
震源=
defaultWorkflow.getSource();
最终竣工阶段未来=
source.take(1.runWith)(Sink.seq(),materializer);
最终列表结果=future.tocompleteFuture().join();
assertEquals(1,result.size());
assertEquals(result.get(0).getBody(),messageBody);
}
public void generateSourceData(字符串queueUrl、字符串messageBody){
客户
.sendMessage(
SendMessageRequest.builder().queueUrl(queueUrl).messageBody(messageBody.build())
.join();
}
private void initClient()抛出URISyntaxException{
System.setProperty(SdkSystemSetting.CBOR_ENABLED.property(),“false”);
AwsCredentials credentials=AwsBasicCredentials.create(“somekey”、“somevalue”);
StaticCredentialsProvider=StaticCredentialsProvider.create(凭据);
客户=
SqsAsyncClient.builder()
.region(region.of(Localstack.getDefaultRegion()))
.httpClient(AkkaHttpClient.builder().withActorSystem(ActorSystem.create()).build())
.证书提供者(提供者)
.endpointOverride(新URI(Localstack.INSTANCE.getEndpointSQS())
.build();
}
受保护的字符串initSQS(字符串queueName)引发URI语法异常{
initClient();
客户
.createQueue(CreateQueueRequest.builder().queueName(queueName).build())
.join()
.queueUrl();
GetQueueUrlResponse=client.getQueueUrl(GetQueueUrlRequest.builder().queueName(queueName.build()).join();
System.out.println(“使用队列”+响应);
info(“使用队列{}”,响应);
返回response.queueUrl();
}
启用调试时,我看到此错误将永远重复:
[信息][调试]s.a.a.c.i.ExecutionInterceptorChain-创建
将按以下顺序应用拦截器的拦截器链:
[software.amazon.awssdk.awscore.interceptor。HelpfulUnknownHostExceptionInterceptor@41a58812,
software.amazon.awssdk.services.sqs.internal。MessageMD5ChecksumInterceptor@4f626e56,
software.amazon.awssdk.protocols.query.interceptor。QueryParametersToBodyInterceptor@4b5de362]
[信息][调试]s.a.a.c.i.ExecutionInterceptorChain-拦截器
'software.amazon.awssdk.protocols.query.interceptor。QueryParametersToBodyInterceptor@4b5de362'
使用modifyHttpRequest方法修改了消息。[信息][调试]
s、 a.a.请求-发送请求:
DefaultSdkHttpFullRequest(httpMethod=POST,protocol=http,
主机=localhost,端口=4566,encodedPath=,
headers=[amz sdk调用id、内容长度、内容类型、,
用户代理],查询参数=[])[info][debug]s.a.a.s.Aws4Signer-
要签名的AWS4字符串:AWS4-HMAC-SHA256[info]20201230T233655Z[info]
20201230/us-east-1/sqs/aws4_请求[信息]
5e95b0e67072e57434cb0da9516ef2ef4c747760bda87e9207161f9834d6dc01
[信息][调试]s.a.a.请求-收到的错误响应:500[信息]
[调试]s.a.a.request-检测到可重试错误。将在47毫秒后重试。
请求尝试编号2[info][debug]s.a.a.Request-重试
请求:DefaultSdkHttpFul