🕐 Tempo di lettura: 2 minuti

Hai mai orchestrato servizi… che poi falliscono? Se ti capita di gestire chiamate a sistemi esterni (trascrizione, storage, AI, ecc.), sai che prima o poi qualcosa potrebbe smettere di funzionare. Ma invece di annidare try/catch, puoi costruire qualcosa di più robusto e pulito.

In Athanatos, "progettino" personale cui sto lavorando ultimamente, ho usato una combinazione di:

📌 Struttura del flusso

L'organizzazione dei file riflette esattamente questa logica:

service/
├── transcriber/
│   ├── BaseTranscriberService
│   ├── FallbackTranscriberService
│   ├── ITranscriberService
│   ├── PrimaryTranscriberService
│   └── TranscriberService
├── OpenAIService
├── OrchestratorService
└── StorageService

Il cuore del meccanismo è davvero poche righe: il TranscriberService prova il primary e, se questo fallisce, passa al fallback grazie a onErrorResume:

@Slf4j
@Service
@RequiredArgsConstructor
public class TranscriberService implements ITranscriberService {

    protected final PrimaryTranscriberService primaryTranscriberService;
    protected final FallbackTranscriberService fallbackTranscriberService;

    public Mono<TranscriptionResponse> transcribe(final PsychometricFileData fileData) {
        return primaryTranscriberService.transcribe(fileData)
                .doOnError(throwable -> log.error("<-- primary service failed, trying fallback implementation"))
                .onErrorResume(throwable -> fallbackTranscriberService.transcribe(fileData));
    }
}

🔍 Perché funziona?

Lo stesso approccio si adatta bene anche ad altri contesti reali, come i pagamenti multi-provider (PayPal, Apple Pay, ecc.) o le notifiche multi-canale (email, SMS, push), dove fallback e comportamento intercambiabile sono fondamentali!

Alla prossima pillola! ☕