Progettazione dell'elaborazione del flusso di lavoro e dei callback nell'applicazione multistrato asp.net

0

Sto cercando un consiglio di progettazione per il seguente scenario:

Applicazione a tre livelli:

  1. MVC Portal (solo l'app frontend in realtà)
  2. Business logic WebApi (tutta la magia accade qui)
  3. Servizi connessi (solo i servizi di elaborazione file qui)

Il portale non è a conoscenza di alcun database, servizi di elaborazione, ecc. comunica solo con Business WebApi

Quindi, lo scenario aziendale è

  1. L'utente carica un file nel portale
  2. Il portale lo invia a WebApi
  3. Il file viene valutato, un "progetto" viene creato per questo nel database ecc.
  4. Il flusso di lavoro è costruito sulla base del risultato della valutazione del file e forse anche di alcune impostazioni del progetto.

Il flusso di lavoro è costituito da passaggi, che sono essenzialmente attività di elaborazione gestite dai servizi connessi (il terzo livello).

Ad esempio:

  • Passaggio 1 - CleanerService
  • Passaggio 2 - PreprocessoreServizio
  • Passaggio 3 - PostprocessorService
  • Passaggio 4 - PublisherService

Ognuno di questi passaggi richiederà parecchio tempo, quindi invece di attendere attivamente il risultato, invierò semplicemente una richiesta e restituirò un risultato immediato (accettato per l'elaborazione).

Quindi, una volta che un servizio viene eseguito con il file, invierà una richiamata a Business WebApi. Molto probabilmente, tornando al controller da cui proveniva la richiesta.

Avrò una semplice classe WorkflowManager che cercherà il database per il flusso di lavoro per un determinato file, otterrà un ID successivo, identificherà il tipo di servizio e invierà il file a questo servizio.

Ecco dove inizia la domanda effettiva

Come gestisco correttamente una comunicazione tra ciascuno dei controller di servizio e un WorkflowManager?

Ad esempio, il controller CleanerService (nel codice para;))

public class CleanerServiceController : ApiController
{
    [HttpPost]
    public async Task<StepTriggerResult> SendCleaningJob(File file)
    {
        // this action is called by the Portal
        // and it uses its HttpClient to send another Post to a proper service
    }

    [HttpPost]
    public async Task CleaningCompleteCallback(File file)
    {
         //I could maybe call a workflow manager here e.g.
         this.workflowManager.StartNextStep(file);
         // the start next step would figure out the controller for the next step service and call action similar to SendCleaningJob(file);
    }
}

Tuttavia, aggiungere workflowManager ai controller per le azioni sembra un po 'hacky. Penso che sarebbe meglio averlo centralizzato in qualche modo, piuttosto che sparsi su tutti i controller. Forse un controller API condiviso per tutti i callback sarebbe meglio.

Qualche idea?

    
posta Bartosz 31.05.2017 - 20:32
fonte

2 risposte

2

"Il file viene valutato, un" progetto "viene creato per esso nel database ecc."

Per tua stessa ammissione, la logica di business è strettamente collegata al tuo database. So che questo non è legato alla tua domanda reale, ma è qualcosa che dovresti essere a conoscenza. A mio parere, è meglio che il front end sia a conoscenza del datalayer che non sia consapevole della logica di business. È molto difficile separare la logica aziendale e l'accesso ai dati una volta che sono strettamente accoppiati.

Questo mi porta a una domanda che ho per te, hai una ragione convincente per posizionare la tua logica aziendale in una web API invece di una dll / sll? Puoi benissimo, ma la tua domanda non ha chiarito che lo fai.

Posizionare la logica aziendale in un ambiente Web crea un significativo sovraccarico di progettazione, incluso, ma non limitato al problema che stai facendo qui.

Se il tuo livello aziendale non fosse basato sul Web, saresti in grado di coordinare facilmente i passaggi utilizzando gli eventi.

Inoltre, il secondo livello può essere chiamato in modo asincrono, non esiste alcun motivo valido per chiamare il livello 3 in modo asincrono. Puoi semplicemente attendere che i passaggi vengano completati con le chiamate sincrone da 2 a 3, a condizione che il livello 1 continui.

Potresti anche usare il modello di controllo dei reclami; assegni ad ogni richiesta un ID, quindi continua. Una volta completato il servizio di pulizia, richiama il layer 2 con l'ID. Ma ancora, non vedo come sia necessario.

    
risposta data 31.05.2017 - 20:54
fonte
1

Ci ho voluto un minuto per digerire la tua architettura. È insolito e vedo alcuni problemi con esso.

  1. Hai uno stack di applicazioni che si allontana dalla tipica relazione master-slave. In alcuni casi, WebApi chiama il servizio e in altri il servizio chiama l'API. Normalmente, le chiamate vengono sempre avviate dal livello superiore nello stack e il livello inferiore può solo richiamare livelli al di sotto di esso.

    Perché questo è un problema? Considerare il caso in cui è necessario aggiungere un nuovo bit di logica e un nuovo callback. Per implementare il nuovo servizio, è necessario disporre della nuova WebAPI per supportare il callback e per poter distribuire WebAPI, è necessario disporre del nuovo servizio. Questo tipo di relazione circolare può rendere molto doloroso gli scenari di aggiornamento e distribuzione, perché tutto deve essere eseguito in un attimo.

  2. Sono in esecuzione transazioni a esecuzione prolungata in un servizio e un flusso di lavoro che dipende da un callback in tempo reale. Pensa alle tue modalità di fallimento e potresti iniziare a chiedervi come gestirle. Cosa succede se una callback fallisce a causa di un problema di rete transitoria? Cosa fare se è necessario riciclare i servizi mentre è in esecuzione una transazione a esecuzione prolungata? Cosa succede se i tuoi processori sono troppo occupati per gestire nuovi file al momento? Le cose sul web non sono buone per questo.

Suggerirei un approccio leggermente diverso

  1. Applicazione Web ("portale") semplicemente per caricare file. Potrebbe anche essere una semplice applicazione a due livelli, per cui non sarebbe richiesto alcun livello di servizio.

  2. Uno o più demoni, attività programmate o servizi Windows che cercano i file caricati, li spostano in una posizione in cui possono essere lavorati (nel database se lo desideri, anche se preferirei i file flat su una SAN personalmente), e crea e inizializza i flussi di lavoro per loro.

  3. Una struttura di database che definisce un flusso di lavoro in volo e quali passaggi sono già stati completati. Ogni flusso di lavoro dovrebbe avere un identificativo univoco.

  4. Una struttura di code (ad esempio una tabella di database) che indica quali flussi di lavoro sono riservati per l'elaborazione, in fase di elaborazione o di rilascio recente dall'elaborazione.

  5. Un'altra attività / servizio che legge la coda, riserva i file per l'elaborazione e li elabora. Devi prima prenotarli perché potresti finire con più di un processore in esecuzione, ad es. se hai bisogno di ridimensionare.

  6. Un meccanismo di recupero che consente di riacquisire gli elementi della coda non aggiornata. Ciò sarà utile se il sistema si arresta mai ed è necessario ripristinarlo.

  7. Strumenti di monitoraggio per controllare lo stato dei servizi, la dimensione della coda e gli avvisi di NoC se i servizi falliscono o la coda diventa troppo lunga.

Questo sarebbe un approccio molto più robusto. I servizi Windows non sono così sexy come le web API ma sono uno strumento migliore per il problema.

    
risposta data 09.06.2017 - 22:03
fonte

Leggi altre domande sui tag