Impedisce la creazione di più entità

1

In un'applicazione che sto sviluppando, abbiamo integrato una API di terze parti. Uno dei casi d'uso consiste in un utente del nostro sistema che compila un modulo e lo invia. Questo ci porta a mappare il modulo a un modello di richiesta API e a pubblicarlo sull'API di terze parti. Questo avvia un processo esterno, i cui dettagli non sono rilevanti. Tuttavia otteniamo una risposta con un ID univoco per il processo creato e, quando otteniamo ciò, creiamo un'entità aziendale che modella il processo avviato in modo da poterlo tenere traccia e aggiornare, ecc. È necessario notare che ciascun utente ( account) può avviare questo processo solo una volta (ciò viene applicato controllando se l'account ha un processo associato).

Il problema che stiamo avendo è che se un utente tocca due volte di inviare o di riposare, c'è la possibilità che invochino l'inizio di un altro processo prima che abbiamo avuto il tempo di ottenere la risposta dall'api di terze parti e accoppiata l'entità di processo con l'account utente. L'API di terze parti non si preoccupa se due richieste sono identiche.

Stiamo cercando un modo ordinato per "bloccare" l'account in modo che non possa essere utilizzato per inviare più richieste alla terza parte fino a quando il caso di utilizzo non è completo e otteniamo una risposta non riuscita. Un modo molto hacky per realizzarlo sarebbe non appena viene avviato il caso d'uso, salvare un'entità "fittizia" con qualche stringa senza senso come se fosse id nel database e associarlo all'account. Quando riceviamo la nostra risposta dall'API di terze parti, possiamo eliminare il dummy e procedere normalmente.

Allo stesso modo, potremmo consentire la creazione delle entità di processo senza id da parte di terze parti, e quindi l'aggiorneremo quando avremo una risposta positiva. Ciò sembra leggermente più pulito, ma sarebbe bello se potessimo evitare di allentare i vincoli sull'entità (questo ID non dovrebbe mai cambiare e nel modello è considerato un identificatore univoco costante). Questo potrebbe benissimo essere pedante, ma se ci sono altri percorsi mi piacerebbe esplorarli.

Se è rilevante, l'utente invia il modulo come POST HTTP, lo processiamo lato server in un'applicazione ASP.NET utilizzando Entity Framework come un ORM e inviamo la richiesta alla terza parte utilizzando un client che internamente utilizza un HttpClient .NET standard.

Potrebbe anche essere utile notare che anche se rileviamo che è stato creato un duplicato, non possiamo semplicemente cancellare la riga e notificare alla terza parte (senza un notevole sovraccarico di lavoro)

    
posta sara 31.03.2016 - 14:28
fonte

2 risposte

1

Nella mia azienda abbiamo avuto un problema simile prima, dato che alcuni POST stavano ottenendo due volte in prossimità molto ravvicinata.

Se hai un solo server web, puoi utilizzare il blocco interno come un HashTable o un Set con ID utente che sono in sospeso per l'elaborazione, tutto questo sincronizzato con un semaforo o blocchi.

Diventa complicato quando ci sono più server web e ogni POST può arrivare a un server diverso. In questo caso, è necessaria una sorta di autorità centrale che funga da blocco. L'approccio al database va bene, ma avrai un sacco di IO e prestazioni pessime. Abbiamo usato memcached per questo. Basta inserire una chiave con l'id utente e alcuni dati senza senso (un 1 per esempio). Se esiste già una chiave, il metodo di aggiunta di memcache restituirà un errore, il che significa che lo stesso utente ha inviato un POST prima.

A seconda della tua logica di business puoi lasciare che la chiave scada da sola (impostando alcuni time-to-live sensibili), oppure puoi eliminarla quando il processo termina.

    
risposta data 31.03.2016 - 20:59
fonte
0

Il problema è di impedire che lo stesso servizio venga invocato due volte nello stesso momento, ho già riscontrato questo problema, semplicemente creo il metodo take methodName come parametro e ottengo il metodo per reflection e controlla se questo metodo è già in esecuzione o meno.

  public void DoWork(string methodName) 
  {  
  var action = this.GetType().GetMethod(methodName); 
  JobStatus value = null;   
  _jobs.TryGetValue(methodName, out value); 
  if (value != null && value.IsRunning)  
  { // Do Nothing } 
  else { 
  if (value == null) 
      value = new JobStatus  
      { SyncObject = new object() }; 
  lock (value.SyncObject) 
  { 
      if (!value.IsRunning)  
       { 
           value.IsRunning = true;
           _jobs.TryAdd(methodName, value); 

             action.Invoke(this, null); 
           } 
        } 
  }

Lavori è un dizionario contiene tutti i servizi in esecuzione e JobStatus è un modello semplice

    
risposta data 31.03.2016 - 19:47
fonte

Leggi altre domande sui tag