Merge pull request 'refactor: add retry mechanism to Feign clients for improved resilience' (#36) from refactor-architecture into main

Reviewed-on: #36
This commit is contained in:
rov 2026-03-26 14:04:20 -03:00
commit baeffd6f15
5 changed files with 64 additions and 3 deletions

View File

@ -3,15 +3,28 @@ package com.magamochi.catalog.client;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.resilience.annotation.Retryable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(name = "aniList", url = "https://graphql.anilist.co")
public interface AniListClient {
@PostMapping
@Retryable(
maxRetries = 5,
delay = 1000,
multiplier = 2,
maxDelay = 5000,
includes = Exception.class)
MangaResponse getManga(@RequestBody GraphQLRequest request);
@PostMapping
@Retryable(
maxRetries = 5,
delay = 1000,
multiplier = 2,
maxDelay = 5000,
includes = Exception.class)
MangaSearchResponse searchManga(@RequestBody SearchGraphQLRequest request);
record GraphQLRequest(String query, Variables variables) {

View File

@ -3,6 +3,7 @@ package com.magamochi.catalog.client;
import java.time.OffsetDateTime;
import java.util.List;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.resilience.annotation.Retryable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
@ -10,9 +11,21 @@ import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "jikan", url = "https://api.jikan.moe/v4/manga")
public interface JikanClient {
@GetMapping
@Retryable(
maxRetries = 3,
delay = 1000,
multiplier = 2,
maxDelay = 5000,
includes = Exception.class)
SearchResponse mangaSearch(@RequestParam String q);
@GetMapping("/{id}")
@Retryable(
maxRetries = 3,
delay = 1000,
multiplier = 2,
maxDelay = 5000,
includes = Exception.class)
MangaResponse getMangaById(@PathVariable Long id);
record SearchResponse(List<MangaData> data) {

View File

@ -4,18 +4,37 @@ import com.magamochi.model.dto.MangaDexMangaDTO;
import java.util.List;
import java.util.UUID;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.resilience.annotation.Retryable;
import org.springframework.web.bind.annotation.*;
@FeignClient(name = "mangaDex", url = "https://api.mangadex.org")
public interface MangaDexClient {
@GetMapping("/manga/{id}")
@Retryable(
maxRetries = 3,
delay = 1000,
multiplier = 2,
maxDelay = 5000,
includes = Exception.class)
MangaDexMangaDTO getManga(@PathVariable UUID id);
@GetMapping("/manga/{id}/feed")
@Retryable(
maxRetries = 3,
delay = 1000,
multiplier = 2,
maxDelay = 5000,
includes = Exception.class)
MangaDexMangaFeedDTO getMangaFeed(
@PathVariable UUID id, @RequestParam("contentRating[]") List<String> contentRating);
@GetMapping("/manga/{id}/feed")
@Retryable(
maxRetries = 3,
delay = 1000,
multiplier = 2,
maxDelay = 5000,
includes = Exception.class)
MangaDexMangaFeedDTO getMangaFeed(
@PathVariable UUID id,
@RequestParam int limit,
@ -23,6 +42,12 @@ public interface MangaDexClient {
@RequestParam("contentRating[]") List<String> contentRating);
@GetMapping("/at-home/server/{chapterId}")
@Retryable(
maxRetries = 3,
delay = 1000,
multiplier = 2,
maxDelay = 5000,
includes = Exception.class)
MangaChapterDataDTO getMangaChapter(@PathVariable UUID chapterId);
record MangaDexMangaFeedDTO(

View File

@ -2,11 +2,18 @@ package com.magamochi.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.resilience.annotation.Retryable;
import org.springframework.web.bind.annotation.*;
@FeignClient(name = "ntfy", url = "${ntfy.endpoint}")
public interface NtfyClient {
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
@Retryable(
maxRetries = 3,
delay = 1000,
multiplier = 2,
maxDelay = 5000,
includes = Exception.class)
void notify(@RequestBody Request dto);
record Request(String topic, String message, String title) {}

View File

@ -1,5 +1,7 @@
package com.magamochi.image.queue.consumer;
import static java.util.Objects.nonNull;
import com.magamochi.common.queue.command.ImageFetchCommand;
import com.magamochi.common.queue.command.ImageUpdateCommand;
import com.magamochi.image.queue.producer.ImageUpdateProducer;
@ -21,8 +23,9 @@ public class ImageFetchConsumer {
log.info("Received image fetch command: {}", command);
var imageId = imageFetchService.fetchImage(command.url(), command.contentType());
imageUpdateProducer.publishImageUpdateCommand(
new ImageUpdateCommand(command.entityId(), imageId), command.contentType());
if (nonNull(imageId)) {
imageUpdateProducer.publishImageUpdateCommand(
new ImageUpdateCommand(command.entityId(), imageId), command.contentType());
}
}
}