簡體   English   中英

Webflux 訂閱者

[英]Webflux subscriber

我目前面臨一個關於在 switchIfEmpty function 中保存 redis 的問題。 可能與我在反應式編程中相當新的事實有關,不幸的是我很難找到有關它的適當示例。

但是我已經能夠解決它,但我很確定有更好的方法來解決它。 這是我現在寫的:

public Mono<ResponseEntity<BaseResponse<Content>>> getContent(final String contentId, final String contentType){
    return redisRepository.findByKeyAndId(REDIS_KEY_CONTENT, contentId.toString()).cast(Content.class)
               .map(contentDTO -> ResponseEntity.status(HttpStatus.OK.value())
                                                .body(new BaseResponse<>(HttpStatus.OK.value(), HttpStatus.OK.getReasonPhrase(), contentDTO)))
               //here I have to defer, otherwise It would never wait for the findByKeyAndId 
               .switchIfEmpty(Mono.defer(() -> {
                   Mono<ResponseEntity<BaseResponse<Content>>> responseMono = contentService.getContentByIdAndType(contentId, contentType);
                   
                   //so far I understood I need to consume every stream I have, in order to actually carry out the task otherwise will be there waiting for a consumer.
                   //once I get what I need from the cmsService I need to put it in cache and till now this is the only way I've been able to do it
                   responseMono.filter(response -> response.getStatusCodeValue() == HttpStatus.OK.value())
                               .flatMap(contentResponse -> redisRepository.save(REDIS_KEY_CONTENT, contentId.toString(), contentResponse.getBody().getData()))
                                        .subscribe();
                   //then I return the Object I firstly retrived thru the cmsService
                   return responseMono;
               }
    ));
}

有什么更好的方法的線索或建議嗎? 預先感謝您的幫助!

從最佳實踐的角度來看,有一些事情不是很好,這可能並沒有完全按照你的想法做:

  • 您正在訂閱自己,這通常是出現問題的明顯跡象。 除了特殊情況,訂閱通常應該留給框架。 這也是您需要Mono.defer()的原因 - 通常,在框架在正確的時間訂閱您的發布者之前什么都不會發生,而您自己管理該發布者的訂閱生命周期。
  • 該框架仍將在那里訂閱您的內部發布者,只是您返回的Mono對其結果沒有任何作用。 因此,您可能會調用contentService.getContentByIdAndType()兩次,而不僅僅是一次 - 一次是在您訂閱時,一次是在框架訂閱時。
  • 訂閱這樣的內部發布者會創建一個“即發即棄”類型 model,這意味着當您的反應方法返回時,您不知道 redis 是否實際上已經保存了它,如果您依賴它,這可能會導致問題以后的結果。
  • 與上面無關,但是contentId已經是一個字符串,你不需要在它上面調用toString() :-)

相反,您可能會考慮在您的switchIfEmpty()塊中使用delayUntil - 如果響應代碼正常,這將允許您將值保存到 redis,延遲直到發生這種情況,並在完成后保留原始值。 代碼可能看起來像這樣(如果沒有完整的示例,很難說這是否完全正確,但它應該給你一個想法):

return redisRepository
        .findByKeyAndId(REDIS_KEY_CONTENT, contentId).cast(Content.class)
        .map(contentDTO -> ResponseEntity.status(HttpStatus.OK.value()).body(new BaseResponse<>(HttpStatus.OK.value(), HttpStatus.OK.getReasonPhrase(), contentDTO)))
        .switchIfEmpty(
                contentService.getContentByIdAndType(contentId, contentType)
                        .delayUntil(response -> response.getStatusCodeValue() == HttpStatus.OK.value() ?
                                redisRepository.save(REDIS_KEY_CONTENT, contentId, contentResponse.getBody().getData()) :
                                Mono.empty())
        );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM