Facciata sincrona che nasconde il servizio web asincrono

6

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.

    
posta Torbjørn 11.01.2016 - 23:02
fonte

2 risposte

3

Penso che fare in modo che i clienti attendono le loro richieste web non è ottimale. Anche i secondi sono troppi.

Un modo migliore a mio parere è di restituire immediatamente la richiesta web, eseguire il servizio asincrono e fare il polling del client a intervalli regolari o configurare molto meglio un canale di comunicazione con il client sotto forma di websocket, per esempio.

Modifica:

Considerate le nuove informazioni che il cliente non può essere cambiato, penso che l'approccio migliore sarebbe:

Ogni nodo web ha un ID istanza, quando chiami il servizio asincrono gli dai l'endpoint /callback/instanceId e questo endpoint chiama WebNodes[instanceId].sendResponse() .

Devi tenere un elenco di webnode del genere ma non devi eseguire il polling dei redis continuamente per vedere quando la risposta è tornata, non è necessario eseguire il poll e il thread sleep in un ciclo non è necessario.

    
risposta data 11.01.2016 - 23:44
fonte
1

Nel mio ambiente di programmazione (MacOS X / iOS) è piuttosto banale - creo un semaforo, avvio la richiesta asincrona, la richiesta asincrona sbloccherà il semaforo quando è terminata, quindi bloccherò il semaforo (che si sveglierà quando viene eseguita la richiesta asincrona). Forse sei o otto righe di codice.

D'altro canto, le richieste sincrone, pur essendo più facili da gestire, hanno l'effetto negativo di dover attendere il risultato, che per qualsiasi tentativo di mostrare un'interfaccia utente è un assoluto no-no. Quindi tali richieste sincrone dovrebbero essere utilizzate solo su un thread in background.

    
risposta data 12.01.2016 - 10:18
fonte

Leggi altre domande sui tag