Como transformar um Mono em um verdadeiro assíncrona (não reativa!) chamada de método?

0

Pergunta

Eu tenho um método

@Service
public class MyService {
    public Mono<Integer> processData() {
        ... // very long reactive operation
    }
}

No fluxo normal do programa, eu chamo esse método de forma assíncrona através de um Kafka evento.

Para fins de teste que eu preciso para expor o método como um serviço da web, mas o método deve ser exposto como assíncrona: retornando apenas o código HTTP 200 OK ("solicitação de aceite"), e continuando o processamento de dados no plano de fundo.

É OK (= não tem quaisquer efeitos colaterais indesejados) apenas para chamar Mono#subscribe() e o retorno do método de controlador?

@RestController
@RequiredArgsConstructor
public class MyController {
    private final MyService service;

    @GetMapping
    public void processData() {
        service.processData()
            .subscribeOn(Schedulers.boundedElastic())
            .subscribe();
    }
}

Ou é melhor fazer como esta (aqui estou confuso com o aviso de que o IntelliJ, talvez o mesmo que https://youtrack.jetbrains.com/issue/IDEA-276018 ?):

public Mono<Void> processData() {
    service.processData()
        .subscribeOn(Schedulers.boundedElastic())
        .subscribe(); // IntelliJ complains "Inappropriate 'subscribe' call" but I think it's a false alarm in my case(?)
    return Mono.empty();
}

Ou alguma outra solução?

2

Melhor resposta

3

É OK (= não tem quaisquer efeitos colaterais indesejados) apenas para chamar Mono#subscrever() e retornar a partir do método de controlador?

Há efeitos colaterais, mas você pode ser ok viver com eles:

  • Ele realmente é fogo, e esqueça - o que significa que enquanto você nunca vai ser notificado sobre uma sucesso (o que a maioria das pessoas percebe), você também vai nunca ser notificado sobre uma falha (que muito menos pessoas percebem.)
  • Se o processo deixa de responder por alguma razão, que o publisher nunca será concluída, e você vai ter nenhuma maneira de saber. Uma vez que você está assinando em fronteira elástico threadpool, ele também vai amarrar um daqueles limitado de threads indefinidamente muito.

O primeiro ponto, você pode estar bem com, ou você pode querer colocar algumas log de erro de mais para baixo que reativa a cadeia como um efeito colateral de alguma forma, então você tem pelo menos uma notificação interna, se algo der errado.

Para o segundo ponto, eu recomendo colocar uma (generoso) de tempo de espera em seu método de chamada, de modo a que pelo menos é cancelado, se ainda não concluída em um período de tempo, e não está mais deslocado cerca de consumo de recursos. Se você estiver executando uma tarefa assíncrona, então este não é um grande problema, pois ele só vai consumir um pouco de memória. Se você está de moldagem de uma chamada de bloqueio elástica programador, em seguida, este é o pior no entanto, como você está amarrando um segmento em que threadpool indefinidamente.

Eu também pergunta por que você precisa para usar o elástico delimitado programador em todos os aqui - é utilizado para o acondicionamento de bloqueio de chamadas, o que não parece ser o fundamento de que este caso de uso. (Para ser mais claro, se o seu serviço for de bloqueio, em seguida, você deve envolvê-la no elástico programador - mas se não há nenhuma razão para fazê-lo.)

Finalmente, este exemplo:

public Mono<Void> processData() {
    service.processData()
        .subscribeOn(Schedulers.boundedElastic())
        .subscribe();
    return Mono.empty();
}

...é um brilhante exemplo do que não fazer, como você está criando um tipo de "impostor reativa método" - alguém pode muito razoavelmente se inscrever para que retornou editora pensamento será concluída quando o subjacente publisher completa, o que, obviamente, não é o que está acontecendo aqui. Usando um void tipo de retorno e, portanto, não retornar nada é a coisa correta a fazer nesse cenário.

2021-11-23 16:54:58
1

A sua opção com o seguinte código é realmente ok:

@GetMapping
public void processData() {
    service.processData()
        .subscribeOn(Schedulers.boundedElastic())
        .subscribe();
}

Este é, na verdade, o que você faz em um @Scheduled método que simplesmente não retorna nada e você explicitamente subscrever o Mono ou Flux para que os elementos são emitidos.

2021-11-23 08:36:44

Em outros idiomas

Esta página está em outros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................