Domanda di progettazione: il server restituisce risultati parziali per l'ottimizzazione

0

Ho un servizio che invia una serie di query al server in una singola chiamata e agisce sulle decisioni prese dal server. Per prima cosa introdurrò ciò che ho già e le domande seguiranno.

   public class Item {
    int id;
    int version;
    String description;
}

public class RequestObject {
    Item key;
    List<Item> candidates;
}

public class ResultObject {
    Item key,
    Item candidate,
    Boolean isActionable;
}

public class Client {
    List<ResultObject> post(RequestObject request) {
        // Makes a rest call to the server and returns the results
}
}

/** Server side **/
public class ServiceServlet {
    private ActionDecider actionDecider;
    List<ResultObject> processRequest(RequestObject request) {
        List<ResultObject> results = new ArrayList<>();
        for(Item c : request.candidates) {
            // decider reads values of key and c from database, returns the results
            results.add(actionDecider.decide(request.key, c));
        }
        return results;
    }
}


/** Client side **/
public class ClientService {
    private ResultUpdater updater;
    public void processMessage(Item key, List<Item> candidates) {
        RequestObject request = new RequestObject(key, candidates);
        for(ResultObject result : client.post(request)) {
            if(result.isActionable) {
                // update values of key and c in database, if key provided has a different version that in the database, throws exception
                updater.update(result.key, result.candidate);
            }
        }
    }
}

Nota:

  • Il numero di candidati in una richiesta è di circa 100. E in media recuperiamo circa 5 coppie di azioni.
  • actionDecider.decide è un'operazione costosa, quindi vogliamo evitare di eseguirla inutilmente più di una volta per la stessa coppia di articoli.

Problema: quando ci sono più risultati utilizzabili e il programma di aggiornamento aggiorna la chiave la prima volta, il valore nel database cambia e quindi il resto dei risultati è obsoleto. Il resto dei messaggi deve essere rivalutato chiamando il servizio lato server prima che possano essere aggiornati.

Una soluzione semplice sarebbe inviare ciascun candidato alla volta come richiesta al server, aggiornare il risultato se possibile e continuare con il candidato successivo. Tuttavia, questo rende K il numero di richieste invece di fare una singola richiesta. Ciò significa che subiremo quasi K volte più la latenza della rete.

public class ClientService {
    private ResultUpdater updater;
    public void processMessage(Item key, List<Item> candidates) {
        for(Item candidate : candidates) {
            RequestObject request = new RequestObject(key, candidate);
            ResultObject result = client.post(request).get(0);
            if(result.isActionable) {
                // update values of key and c in database, if key provided has a different version that in the database, throws exception
                updater.update(result.key, result.candidate);
            }
        }
    }
}

La soluzione alternativa che sto pensando è la seguente. Dal momento che anche noi possediamo il servizio server, possiamo modificare l'oggetto richiesta in modo che contenga un flag che chiede al server di restituire il primo risultato utilizzabile saltando i candidati rimanenti nella richiesta. Allo stesso modo, possiamo creare un altro client che tenga traccia dei candidati che ha già inviato al server per il confronto e quali sono i restanti.

public class OptimizedClient {
    public final RequestObject request;
    private List<Item> remainingCandidates;
    public OptimizedClient(RequestObject request) {
        this.request = request;
        this.remainingCandidates = request.candidates;
    }

    public ResultObject getNextActionable() {
        // makes call to the server with the remaining candidates and check if it got a first set of matched results
        RequestObject remainingRequest = new RequestObject(request.key, request.remaningCandidates);
        // make rest call
        List<ResultObject> results = restClient.post(remainingRequest);
        if(results != null) {
            int from = remainingCandidates.indexOf(results.get(0)) + 1;
            int to = remainingCandidates.size();
            remainingRequest = remainingCandidates.subList(from, to);
            return results.get(0);
        }
        return null;
    }
}

Esiste uno schema standard per questo tipo di problema? In caso contrario, posso apportare miglioramenti alla mia soluzione ottimizzata proposta?

    
posta learnerer 08.10.2016 - 21:11
fonte

1 risposta

1

Problem: When there are multiple actionable results and updater updates the key the first time, the value in the database changes and hence the rest of the results are stale. The rest of the messages have to be re-evaluated by calling the server side service before they can be updated.

Hai ragione, questo sembra essere un problema. Il tuo post è molto generico quindi è difficile ragionare per una soluzione migliore, ma perché l'aggiornamento di una singola risorsa nel database sta influenzando le altre risorse nel database in modo così dirompente? Se possibile, rivalutare la decisione di progettazione che ha portato a questo problema.

    
risposta data 09.10.2016 - 11:19
fonte

Leggi altre domande sui tag