Java SqsAckSink使Akka流永远挂起,导致图形重新启动

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

我正在尝试使用SQS源代码和Localstack实现一个简单的工作流。 如果我添加
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