Sto scrivendo un'app che dovrebbe parlare con un servizio web. Diciamo che è un'app di chat. Dovrebbe ricevere un flusso di nuovi messaggi (in modo che vengano inviati all'interfaccia il più rapidamente possibile), così come inviare i propri messaggi. Inoltre, mi piacerebbe che l'interfaccia fosse il più reattiva possibile, quindi immediatamente dopo che l'utente ha inviato un messaggio, dovrebbe essere visibile nell'elenco dei suoi messaggi. Tuttavia, la rete potrebbe essere difettosa o il server di chat potrebbe non essere disponibile. Pertanto, dopo che l'utente preme il pulsante "invia", non è garantito che il suo messaggio venga consegnato al server. L'app dovrebbe cercare di raggiungere la rete e, in caso di errore, avvisare l'utente. L'utente ha quindi la possibilità di riprovare o rinunciare del tutto.
Sto cercando di trovare un buon design per questo caso d'uso. La mia idea corrente è questa: sto implementando un oggetto proxy per il server di chat - essenzialmente, sto ri-implementando una parte del server stesso. Sto eseguendo due processi separati, uno dei quali mantiene le cronologie dei messaggi che l'utente ha con tutti i suoi colleghi. Supponiamo che l'utente abbia n
peer. Quindi questo processo esegue n+2
thread, di cui:
-
n
è responsabile del polling degli aggiornamenti da ciascun peer e del loro invio a una coda. Chiamiamoli Feed eventi . -
Il thread
1
consuma quella coda ed è responsabile del mantenimento di una copia locale delle cronologie dei messaggi. anche espone un'interfaccia per inviare nuovi messaggi e iscriversi per gli aggiornamenti degli eventi. Chiamiamolo Maintainer dello stato . -
1
thread esegue richieste per inviare nuovi messaggi, che riceve dal Maintainer . Chiamiamolo Sender .
L'interfaccia esposta da Maintainer dello stato è alimentata da ZeroMQ
. È composto da due socket: uno REP
e uno PUB
. In ogni iterazione del ciclo interno, questo thread recupera gli aggiornamenti dalla coda da Feed eventi , li spinge al socket PUB
e controlla le nuove richieste per inviare messaggi dal socket REP
. Per ogni nuova richiesta, invia l'aggiornamento alla cronologia dei messaggi che mantiene (impostando un flag maybe sent
su di esso) e lo trasferisce in un'altra coda. Questa coda viene utilizzata dal Mittente . Per ogni nuovo elemento in coda, tenta di eseguire una richiesta al server di chat. In caso di successo, invia un evento che conferma il successo a una coda che viene utilizzata dal Maintainer dello stato , quindi maybe sent
diventerà sent
. In caso di errore, invia un evento alla stessa coda, in modo che State Maintainer cambierà maybe sent
in not sent
. In entrambi i casi, il risultato viene inviato attraverso il REP
socket.
Il processo UI è connesso al processo proxy tramite due ZeroMQ
socket. Esegue due thread. Il thread primario riceve aggiornamenti sul SUB
socket e gestisce l'interfaccia utente. Parla con il thread secondario tramite due code. Quando l'utente invia un nuovo messaggio, invia tale messaggio alla coda. Il thread secondario lo preleva e lo invia al socket REQ
, memorizzando un ID univoco per quella richiesta. Quando arriva la risposta (che può essere distinta dall'UID), la spinge alla seconda coda, che consente al thread dell'interfaccia utente di aggiornare l'interfaccia.
Quindi vorrei chiedere:
- Questo approccio è buono come approccio generale alla creazione di client di servizio Web resilienti ? Avere un proxy, mantenendo un pezzo dello stato remoto, due canali per lo scambio di informazioni tra il proxy e la logica dell'app?
- Quali sono alcune pratiche generali per risolvere questo problema? Ad esempio, ho sentito che Telegram è molto tollerante ai guasti. Vale la pena sgranocchiare il suo codice di rete ?