Se un singolo errore fallisce un'operazione di massa?

12

Nell'API su cui sto lavorando c'è un'operazione di eliminazione di massa che accetta un array di ID:

["1000", ..., "2000"]

Ero libero di implementare l'operazione di cancellazione come ritenevo opportuno, quindi ho deciso di rendere tutto transazionale: cioè, se un singolo ID non è valido, l'intera richiesta non riesce. Chiamerò questa modalità strict .

try{
savepoint = conn.setSavepoint();

for(id : IDs)
    if( !deleteItem(id) ){
        conn.rollback(savepoint);
        sendHttp400AndBeDoneWithIt();
        return;
    }

conn.commit();
}

L'alternativa (implementata altrove nella nostra suite di software) consiste nel fare tutto ciò che è possibile nel back-end e segnalare guasti in un array. Quella parte del software si occupa di un minor numero di richieste, quindi la risposta non finisce per essere un gigantesco array ... in teoria.

Un bug recente che si è verificato in un server povero di risorse mi ha indotto a guardare nuovamente il codice, e ora sto mettendo in discussione la mia decisione originale - ma questa volta sono motivato più dalle esigenze del business piuttosto che dalle migliori pratiche. Se, ad esempio, non riesco a completare l'intera richiesta, l'utente dovrà riprovare mentre, se un numero di elementi viene cancellato, l'utente può terminare l'azione e quindi chiedere ad un amministratore di fare il resto (mentre io lavoro per correggere il bug !). Questa sarebbe la modalità permissiva .

Ho provato a cercare online qualche indicazione in merito, ma sono venuto a mani vuote. Quindi vengo da te: cosa ci si aspetta di più dalle operazioni di massa di questa natura? Dovrei attenermi più rigorosamente, o dovrei essere più permissivo?

    
posta rath 12.10.2016 - 16:22
fonte

5 risposte

8

Va bene eseguire una versione "rigida" o "bella" di un endpoint di eliminazione, ma devi dire chiaramente all'utente cosa è successo.

Stiamo facendo un'azione di eliminazione con questo endpoint. Probabilmente DELETE /resource/bulk/ o qualcosa di simile. Non sono schizzinoso. Ciò che importa qui è che, indipendentemente dal fatto che tu decida di essere severo o gentile, devi riferire esattamente cosa è successo.

Ad esempio, un'API con cui ho lavorato ha un endpoint DELETE /v1/student/ che ha accettato gli ID collettivi. Mandavamo regolarmente la richiesta durante i test, ottenevamo una risposta 200 e assumevamo che tutto andava bene, solo per scoprire in seguito che tutti quelli presenti nell'elenco erano entrambi nel database ancora (impostato su non attivo) o non effettivamente cancellato a causa di un errore che ha incasinato le future chiamate a GET /v1/student perché abbiamo recuperato i dati che non ci aspettavamo.

La soluzione è arrivata in un aggiornamento successivo che ha aggiunto un corpo alla risposta con gli ID che non sono stati eliminati. Questo è - per quanto ne so - una sorta di best practice.

In conclusione, qualunque cosa tu faccia, assicurati di fornire un modo per far sapere all'utente finale cosa sta succedendo, e possibilmente perché sta andando avanti. Ad esempio, se abbiamo scelto un formato rigoroso, la risposta potrebbe essere 400 - DELETE failed on ID 1221 not found . Se abbiamo scelto una versione "carina", potrebbe essere 207 - {message:"failed, some ids not deleted", failedids:{1221, 23432, 1224}} (scusate la mia scarsa formattazione JSON).

Buona fortuna!

    
risposta data 12.10.2016 - 18:07
fonte
2

Uno dovrebbe essere rigoroso e permissivo.

Di solito, i carichi di massa sono suddivisi in 2 fasi:

  • Validation
  • Caricamento

Durante la fase di validazione, ogni record viene esaminato rigorosamente per assicurarsi che soddisfi i requisiti delle specifiche dei dati. Uno può facilmente ispezionare 10s di 1000s di record in pochi secondi. I record validi vengono posizionati in un nuovo file da caricare, quelli non validi contrassegnati e rimossi e generalmente inseriti in un file separato (file skip). La notifica viene quindi inviata sul / i record / i che non hanno superato la convalida, in modo che possano essere ispezionati e diagnosticati per la risoluzione dei problemi.

Una volta che i dati sono stati convalidati, vengono quindi caricati. Di solito è caricato in lotti se è abbastanza grande da evitare transazioni a lungo termine o se c'è un fallimento sarà più facile da recuperare. Le dimensioni del batch dipendono dalla grandezza del set di dati. Se uno ha solo 1000 record, un lotto sarebbe OK. Qui si può essere un po 'permissivi con errori, ma si potrebbe voler impostare una soglia batch fallita per interrompere l'intera operazione. Forse se [N] fallisce, si fermerebbe l'intera operazione (se il server era inattivo o qualcosa di simile). Di solito, non ci sono errori a questo punto perché i dati sono già stati convalidati, ma se ci sono stati problemi di ambiente o altro, è sufficiente ricaricare i batch che non hanno funzionato. Questo rende il recupero un po 'più facile.

    
risposta data 12.10.2016 - 17:59
fonte
2

Should a single failure fail a bulk operation?

Non c'è una risposta canonica a questo. È necessario esaminare i bisogni e le conseguenze per l'utente e valutare i trade-off. L'OP ha fornito alcune delle informazioni richieste, ma ecco come procedere:

Domanda 1 : "Qual è la conseguenza per l'utente se una singola eliminazione fallisce?"

La risposta dovrebbe guidare il resto del design / comportamento implementato.

Se, come dice l'OP, è semplicemente l'utente a notare l'eccezione e apre un trouble ticket, ma non è influenzato (gli elementi non eliminati non influenzano le attività successive), quindi andrei con permissive con una notifica automatica per te.

Se le eliminazioni fallite devono essere risolte prima che l'utente possa procedere, allora è chiaramente preferibile rigoroso.

Assegnare all'utente l'opzione (ad es., essenzialmente, un flag di ignore-failures con il strict o permissive come predefinito) potrebbe essere l'approccio più user-friendly.

Domanda 2 : "Ci sarebbero problemi di coerenza / coerenza dei dati se le attività successive vengono eseguite con articoli non ancora cancellati ancora nell'archivio dati?"

Ancora una volta, la risposta determinerebbe il miglior design / comportamento. Sì - > Strict, No - > Permissivo, forse - > Strict o User Selected (in particolare se l'utente può dipendere per determinare con precisione le conseguenze).

    
risposta data 13.10.2016 - 16:00
fonte
0

Penso che questo dipenda dal fatto che tu voglia la scalabilità o meno. Se non hai intenzione di avere molti ID, non dovrebbe importare troppo. Se hai intenzione di avere un milione di ID, o meglio ancora, non sono assolutamente sicuro che non accadrà, quindi potresti dedicare un'ora all'eliminazione degli ID solo per ripristinarli completamente a causa di 1 ID non valido.

    
risposta data 12.10.2016 - 17:42
fonte
-1

Direi che un punto importante qui è ciò che significa per una grande quantità di cose da eliminare.

Questi ID sono in qualche modo correlati logicamente, o è solo una convenienza / prestazioni - raggruppamento di questi di questi?

Nel caso in cui, in qualche modo, anche in modo approssimativo, connesso, andrei per strict . Se si tratta solo di una modalità batch (ad esempio, l'utente fa clic su "salva" per i suoi ultimi minuti di lavoro, e solo allora viene trasmesso il batch), quindi andrei per la versione permissive .

Come dice l'altra risposta: In ogni caso, dì "utente" esattamente cosa è successo.

    
risposta data 12.10.2016 - 20:25
fonte