Sto mantenendo un sistema che fornisce una tipica API REST del servizio web sincrono. Instrada ogni richiesta a uno dei numerosi servizi di back-end possibili. Ora c'è un nuovo back-end che voglio usare, ma c'è un problema - ha un'API asincrona - Dovrò fare una richiesta, e quindi attendere una richiesta di callback.
Penso che sia possibile nascondere questa asincronia dietro una facciata sincretizzante. Questa facciata chiamerà l'API asincrona e quindi metterà le richieste web in attesa "in attesa". Quando l'endpoint di richiamata viene richiamato pochi secondi dopo, riprenderà la richiesta Web corretta e risponderà al chiamante originale. Se la richiamata non arriva entro diciamo 10 secondi smetterò di aspettare e rispondo con un errore.
Un fattore complicante è che ho molti nodi web dietro un bilanciamento del carico, ma sto pensando di poter usare una soluzione di storage distribuita come Redis per pubblicare callback in arrivo, in modo che il nodo web corretto possa prenderlo.
La domanda è: è fattibile? O credi che sarà davvero difficile farlo funzionare correttamente? Qualsiasi esperienza che puoi condividere o link a risorse pertinenti sarebbe molto apprezzata. Qualche altro approccio all'utilizzo di un servizio web asincrono in un altro servizio che deve essere sincrono?
Alcuni pseudo-codice di quello che sto pensando:
define rest-endpoint "/foobar" {
call async backend
until 10 seconds has passed {
sleep 1 second
result = redis.get(some_correlation_id)
if (result)
return new Response(result)
}
return new Response("failed")
}
define rest-endpoint "/callback" {
redis.push(some_correlation_id)
}
Notare che se timeout e risposta "failed" non lo faccio (nel mio caso particolare) devo creare alcun tipo di transazione di compensazione verso il back-end, e il cliente è anche libero di riprovare la stessa richiesta in seguito.
Per la cronaca: il sistema è implementato nello stack .NET, ma sono interessato a qualsiasi tecnologia che possa rendere più semplice l'implementazione di qualcosa di simile.
Nota inoltre che probabilmente non userò effettivamente sleep
in un ciclo, ma un qualche tipo di Task
/ futura astrazione.