Hej,
Mam w Springu taką uproszczoną metodę która nasłuchuje topic, ma wykonać logikę i zapisać do bazy (mongo) nową encję, i wrzucić na kafkę message z sukcesem.
Dla prostoty przykłady metoda została okrojona z wszelkich mapperów.
Chciałbym w jakiś w miarę dobry sposób obsłużyć pesymistyczne przypadki.
animalRestaurantService.cook
jest idempotentne i pod spodem ma logikę, która dzwoni RESTem do innych mikroserwisów, więc łatwo może się wywalić.
Oprócz tego inne rzeczy też się mogą wywalić: repository.save
, kafkaTemplate.send
– mogą rzucić wyjątkami.
Dlatego utworzyłem podstawowy RetryTemplate, pod spodem jest skonfigurowany z exponential backoffem i timeoutami.
Czy aktualny kod wygląda w ogóle wygląda normalnie, czy nie budzi jakichś oczywistych 'wtf'? Czego tu brakuje? Jakie są best practices, co rozważyć? O jakich problemach mam w ogóle tutaj myśleć?
Szczególnie ciekawi mnie sytuacja jeśli save się powiedzie, ale kafka się wywali – czy próbować zapewniać tutaj jakoś atomiczność operacji obu operacji (save+kafka publish) np. outbox patternem?
@KafkaListener(topics = KafkaConstants.ANIMALS_BORN, groupId = "well-fed-animals")
public void onAnimalCreated(AnimalBornEvent event) {
try {
retryTemplate.execute((RetryCallback<Void, Exception>) context -> {
final Food food = animalRestaurantService.cook(event.getAnimal());
repository.save(food);
kafkaTemplate.send(KafkaConstants.FOOD_COOKED, new FoodCookedEvent(food));
return null;
});
} catch (final Exception ex) {
log.error("Error during food cooking or sending event to kafka for {}", event, ex);
kafkaTemplate.send(KafkaConstants.ANIMALS_STARVED_TO_DEATH, new StarvedAnimalEvent(event.getAnimal());
}
}
W przypadku niepowodzenia koniecznie chcę to opublikować to na kafkę żeby cofnąć operacje w innym serwisie