Architettura sincrona con repository asincrono

-1

Per mantenere l'architettura pulita del mio microservice node.js, ho controller, servizi e ad es. repository.

Voglio un flusso di dati sincrono: controller - > servizio - > repository - > servizio - > controller. In questo flusso (in una semplice user story) il repository restituisce i dati al servizio e al servizio sul controller. Ma il repository dovrebbe elaborare le richieste allo storage esterno in modo asincrono. Tutto il codice asincrono dovrebbe esistere solo nel repository, il servizio dovrebbe ottenere dati non elaborati.

La mia attuale implementazione:

UserController.js

module.exports.create = function() {
    console.log("In controller: before service call");

    let userDto = JSON.parse(this.request.body);
    let savedUser = userService.createUser(userDto);

    console.log("In controller: after service call");
};

UserService.js

module.exports.createUser = function createUser(userDto) {

    let user = require('../domain/user/User');

    user.login = userDto.login;
    user.password = userDto.password;

    let userRepository = require('../infrastructure/user/UserRepository');

    Q.spawn(function* () {
        console.log("In service before promise resolve");

        let savedUser = yield userRepository.createUser(user);

        console.log("In service after promise resolve");

        return savedUser;
    });

    console.log("In service: after repository call");
};

UserRepository.js

module.exports.createUser = function createUser(user) {
    console.log("In repository: before save call");

    return new Q.Promise(function(resolve, reject) {

        userEntity.save(function(err, savedUser) {

            console.log("In repository: inside callback after save call");

            if (err) {
                console.log("In repository: inside callback before reject");
                reject(Error('Błąd zapisu danych!'));
            } else {
                console.log("In repository: inside callback before resolve");
                resolve(savedUser);
            }
        });
    });
};

Registri:

  • Nel controller: prima della chiamata di servizio
  • In servizio prima della risoluzione della promessa
  • Nel repository: prima di salvare la chiamata
  • In servizio: dopo la chiamata al repository
  • Nel controller: dopo la chiamata di servizio
  • Nel repository: callback interno dopo la chiamata di salvataggio
  • Nel repository: callback interno prima di risolvere
  • In servizio dopo la risoluzione della promessa

Vorrei ottenere la seguente sequenza di log:

  • Nel controller: prima della chiamata di servizio
  • In servizio prima della risoluzione della promessa
  • Nel repository: prima di salvare la chiamata
  • Nel repository: callback interno dopo la chiamata di salvataggio
  • Nel repository: callback interno prima di risolvere
  • In servizio dopo la risoluzione della promessa
  • Nel controller: dopo la chiamata di servizio
posta stein 21.10.2015 - 15:05
fonte

1 risposta

0

Sto scrivendo questa risposta con poca o nessuna conoscenza tecnica sulle funzionalità di Node.js come architettura server. Sto semplicemente parlando al design di alto livello in un modo agnostico alla tecnologia.

Ciò che desideri creare è essenzialmente un'interfaccia sincrona-over-asincrona. Questo è essenzialmente il luogo in cui fornisci un servizio a un cliente che promette una determinata richiesta, che hanno una ragionevole aspettativa di ricevere una risposta dal server in X quantità di tempo. L'espressione alternativa di questo caso d'uso è che nessuna risposta è ricevuta nel tempo X e quindi si verifica un evento di timeout.

Il repository racchiude un'interfaccia asincrona di qualche tipo che non fornisce alcuna garanzia su quando potresti ricevere una risposta. Potrebbe rispondere in meno di un millisecondo o in 8 ore.

La disconnessione è che il tuo microservizio sta essenzialmente promettendo al suo cliente che non può garantire. Questo è un difetto fondamentale nel modello Sync-over-Async ma non necessariamente invalicabile.

Sostanzialmente devi prima garantire l'ordine di esecuzione dei processi in esecuzione in modo da attendere in modo efficace l'interfaccia asincrona per restituire una risposta e terminare l'esecuzione della sua richiamata prima di lasciare il repository. Se non lo fai, proverai una condizione di corsa come nell'esempio che hai descritto nella tua email.

In genere un server delle applicazioni genera un thread di esecuzione per ogni richiesta in ingresso da elaborare. Il thread termina quando una risposta è stata formulata e inviata (di nuovo, non è sicuro se questo è lo stesso in Node.js). Quello che devi fare è fermare il thread di richiesta fino a quando la richiamata ha terminato l'esecuzione.

In secondo luogo, quando interrompi il thread, devi farlo fino a quando non viene raggiunto un timeout prestabilito. In questo modo, se si attende il ritorno del processo asincrono, si evita che il thread si blocchi e il server si blocchi. È quindi possibile restituire un errore di eccezione appropriato sul servizio al client in modo che possano intervenire su di esso.

    
risposta data 21.10.2015 - 16:06
fonte

Leggi altre domande sui tag