2015-10-08 16 views
27

Implementiamo un'API REST, che avvierà più attività di back-end a esecuzione prolungata. Ho letto il ricettario dei servizi Web RESTful e il consiglio è di restituire l'HTTP 202/Accettato con un'intestazione Content-Location che punta all'attività che si sta elaborando. (ad esempio http://www.example.org/orders/tasks/1234) e chiedere al client di eseguire il polling di questo URI per un aggiornamento dell'attività a esecuzione prolungata.API REST a lunga esecuzione con code

L'idea è di fare in modo che l'API REST invii immediatamente un messaggio a una coda, con un ruolo di background che raccolga il messaggio dalla coda e esegua più attività di back-end, utilizzando anche le code. Il problema che vedo con questo approccio è come assegnare un ID univoco all'attività e successivamente consentire al client di richiedere uno stato dell'attività emettendo un GET all'URI Content-Location.

Se l'API REST viene inserita immediatamente in una coda, può generare un GUID e collegarlo come un attributo al messaggio che viene aggiunto alla coda, ma il recupero dello stato della richiesta diventa difficile.

Un'altra opzione sarebbe quella di avere l'API REST immediatamente aggiungere una voce al database (diciamo un ordine, con un nuovo ID ordine), con uno stato iniziale e successivamente inserire un messaggio in coda per dare il via al attività di back ground, che aggiornerebbero successivamente quel record del database. L'API restituirebbe questo nuovo ID ordine nell'URI dell'intestazione Content-Location, affinché il client possa utilizzare quando controlla lo stato dell'attività.

In qualche modo aggiungendo prima la voce del database, quindi aggiungendo il messaggio alla coda sembra indietro, ma solo aggiungendo la richiesta alla coda rende difficile tenere traccia dei progressi.

Quale sarebbe l'approccio consigliato?

Grazie mille per i vostri approfondimenti.

risposta

26

Presumo che il sistema sia simile al seguente. Hai un servizio REST, che riceve richieste dal client. Converte le richieste in comandi che la logica aziendale può comprendere. Hai messo questi comandi in coda. Si dispone di uno o più worker che possono elaborare e rimuovere questi comandi dalla coda e inviare i risultati al servizio REST, che può rispondere al client.

Il tuo problema è che con le tue attività di lunga durata i timeout della connessione client, quindi non è possibile inviare una risposta. Quindi, ciò che puoi fare è inviare un 202 accettato dopo aver messo i comandi nella coda e aggiunto un link di polling, in modo che il client possa effettuare il polling per le modifiche. Le tue attività hanno più attività secondarie quindi è possibile progredire, non solo in sospeso e completare le modifiche di stato.

  1. Se si desidera mantenere il polling, è necessario creare una nuova risorsa REST, che contenga lo stato effettivo e l'avanzamento dell'attività a esecuzione prolungata. Ciò significa che è necessario memorizzare queste informazioni in un database, quindi il servizio REST sarà in grado di rispondere a richieste come GET /tasks/23461/status. Ciò significa che il tuo operatore deve aggiornare il database quando viene completata una sottoattività o l'intera attività.
  2. Se il servizio REST è in esecuzione come daemon, è possibile notificarlo in base allo stato di avanzamento, pertanto la memorizzazione dello stato dell'attività nel database non sarà responsabilità dell'operatore. Questo tipo di servizio REST può anche memorizzare le informazioni nella memoria.
  3. Se si decide di utilizzare websockets per notificare il client, è possibile creare un servizio di notifica. Con REST è necessario rispondere con un ID attività. Dopo di ciò, si restituisce questo ID attività sulla connessione websocket, quindi il servizio di notifica saprà quale connessione websocket è stata sottoscritta agli eventi di una determinata attività. Dopodiché non avrai bisogno del servizio REST, puoi inviare lo stato di avanzamento tramite la connessione websocket a condizione che il client non chiuda la connessione.
  4. È possibile combinare queste soluzioni nel seguente modo. Consenti al servizio REST di creare una risorsa attività, in modo da poter accedere allo stato utilizzando un collegamento di polling. Dopo di ciò, si restituisce un identificatore con 202 che si rimanda attraverso la connessione websockets. Quindi è possibile utilizzare un servizio di notifica per informare il cliente. A mano a mano che il lavoratore informerà il servizio REST, creerà un collegamento come GET /tasks/23461/status e invierà quel collegamento al client attraverso il servizio di notifica. Successivamente il client può utilizzare il link per aggiornarne lo stato.

Penso che l'ultimo sia la soluzione migliore se il servizio REST viene eseguito come un demone. È perché puoi trasferire la responsabilità della notifica a un servizio di notifica dedicato, che può utilizzare web socket, polling, SSE, qualsiasi cosa tu voglia. Può crollare senza uccidere il servizio REST, quindi il servizio REST rimarrà stabile e veloce. Se si restituisce anche un collegamento di aggiornamento manuale con il 202, il client può eseguire l'aggiornamento manuale (assumendo un client controllato dall'essere umano), quindi si avrà qualcosa di gradevole degrado se il servizio di notifica non è disponibile. Non è necessario mantenere il servizio di notifica perché non saprà nulla delle attività, invierà solo i dati ai client. Il tuo operatore non dovrà sapere nulla su come inviare notifiche e su come creare collegamenti ipertestuali. Sarà più semplice mantenere il codice client, poiché sarà quasi un puro client REST. L'unica caratteristica aggiuntiva sarà l'abbonamento per i link di notifica, che non cambia frequentemente.

+0

Grazie mille per i tuoi approfondimenti. Sono tutto per soluzioni pragmatiche, quindi mi sembra sufficiente l'approccio al database singolo. Il modello di attività può essere esteso per includere anche attività secondarie, nel caso in cui l'API supporti la richiesta aggregata. Grazie! – user2079172

+0

Grazie per l'aggiornamento e il suggerimento! :) Questa configurazione sarebbe sicuramente una soluzione praticabile. I nostri integratori potrebbero non essere in grado di mantenere una connessione aperta (sistemi legacy), ma molto probabilmente saranno in grado di fare un sondaggio. Il collegamento di un'API REST e l'approccio 202/Accettato con un bus/coda di servizio è il punto in cui la disconnessione è per me. Idealmente il bus di servizio/coda sarebbe il punto di integrazione per altri sistemi e l'API in questo caso, è solo un altro modo di integrare un altro sistema con il bus di servizio (Channel Adapter). Affinché la tua installazione di suggerimento funzioni, abbiamo bisogno di un altro livello di astrazione che tratti l'aggiornamento update_event – user2079172

+0

così come lo vedo io. Quindi l'API dovrebbe: 1. inserire una nuova riga nella tabella update_event e restituire il nuovo id. 2: inserire immediatamente una nuova richiesta nella coda del bus di servizio. Il cliente può ora eseguire il polling ecc. Ruolo del lavoratore 1: preleva il messaggio di coda e invia il flusso di lavoro di backend. 2: una volta fatto, dovrà aggiornare la tabella update_event con il nuovo URI di risorsa, ecc. Il problema qui è che il ruolo di lavoratore diventerà consapevole di un client con requisiti speciali o? Significa, non è più generico per il sistema di messaggistica? – user2079172