Progetto di classe Stateless con modifica parziale

-1

Ho a che fare con un problema di progettazione. In realtà ho la seguente architettura:

Un'interfaccia Process :

public interface Processor {

    void applyNewConfiguration(final Configuration conf);

    Result process();
}

Un processore MyProcessor che implementa questa interfaccia:

public class MyProcessor implements Processor {

    @Override
    public void applyNewConfiguration(Configuration conf) {
        // Manage configuration which can take a long time
        // Scan dir, fetch BIG files, etc.      
    }

    @Override
    public Result process() {
        // Process regarding the configuration
    }
}

E un Manager che attiva il metodo process di ogni Processor quando necessario:

public class ProcessManager {

    public void execute() {

        //  Eventually apply new configuration to a processor

        // Call process method of Processor
    }
}

Spiego questo: in realtà, all'avvio dell'applicazione, tutti i processori vengono caricati e viene applicata una configurazione. Il caricamento della configurazione può essere molto lungo e non cambia molto spesso, quindi non ho voluto ricreare un Processor ogni volta che voglio farlo elaborare.

Quindi sono giustificato a creare una singola istanza di ciascun processore e, quando necessario, applico una nuova configurazione e poi richiamo il metodo di processo come al solito.

Per me, è un brutto progetto perché sto cambiando il comportamento dei miei processori mentre dovrebbero essere Stateless, ma non so come affrontarlo? Se ho chiamato il metodo di processo mentre viene applicata la configurazione, il comportamento sarà drammatico ...

Ovviamente potrei avere un costruttore in ogni processore con la configurazione come parametro, e ricreare un processore ogni volta, ma la gestione della configurazione è un processo molto lungo quindi non voglio farlo.

Stavo pensando di avere una classe separata (forse ConfigurationManagement ) che può gestire ogni oggetto Configuration , elaborarlo e associarlo a un Pojo (ad esempio in una Map<Configuration,Pojo> ) ma appena una nuova configurazione sarà applicato, quello precedente non sarà garbage collection.

Hai idea di come risolvere questo problema? Sembra abbastanza semplice ma non riesco a trovare alcuna soluzione valida.

    
posta Rouliboy 10.02.2018 - 12:54
fonte

2 risposte

2

Il caching è un compromesso a favore delle prestazioni, mentre costa una maggiore complessità del codice e l'utilizzo della memoria.

Quando memorizziamo le cose in cache dobbiamo considerare: quando invalidare la cache. È uno dei difficili problemi dell'informatica .

Mentre stai realizzando, se non invalidi mai le voci della cache, lo spazio occupato dalla cache non diminuirà mai. Se raggiunge il massimo caricando tutte le configurazioni, potrebbe essere un sacco di memoria, ma potrebbe essere ok. Tuttavia, se nel tuo dominio vengono aggiunte configurazioni, anche se lentamente nel tempo, man mano che le nuove configurazioni vengono visualizzate e memorizzate nella cache, è possibile che si verifichino problemi di perdita di memoria.

L'altro problema con l'invalidazione della cache è cosa succede se la configurazione basata su disco cambia? La tua copia memorizzata nella cache sarà al meglio o, nel peggiore dei casi, sbagliata. Quindi, se questo è un problema nel tuo dominio, ora che stai memorizzando nella cache devi notare o essere informato quando la configurazione del disco cambia. Questa è un'area in cui vediamo il costo della complessità del codice.

(NB: se la configurazione coinvolge più file, e vengono modificati individualmente, si vorrebbe anche un modo per assicurarsi di visualizzare solo le modifiche complete, non un aggiornamento incompleto, ma si tratta di un problema che si avrebbe indipendentemente dal caching .)

Quindi, quello che facciamo in cache è

  1. imposta la notifica delle modifiche sull'entità originale e invalida la cache alla notifica. In alcuni domini, ricaricheremo immediatamente la cache per quell'entità, e in altri ben saremo pigri e ricaricheremo la prossima richiesta. (A seconda della distanza (di rete) tra l'originale e il valore memorizzato nella cache potremmo ancora avere il potenziale di lavorare con entità appena marginali, quindi forse trasportare metadati in modo che il consumatore possa prendere in considerazione o richiedere una versione o timestamp particolare.)

  2. e / o controlla se la configurazione è ancora valida per ogni utilizzo di una voce nella cache.

  3. invecchiano le voci della cache. Esistono vari algoritmi di invecchiamento e possono essere difficili da ottenere. In generale, non vogliamo rimuovere un'entità dalla cache se è attualmente in uso. Quindi, è necessario tenere traccia dell'utilizzo dell'entità della cache. Oltre a ciò si potrebbero invecchiare le voci dopo un certo periodo di tempo senza l'uso. Oppure invecchiare le entità su una soglia di consumo di memoria (quindi è necessario tenere traccia delle dimensioni dell'entità e delle dimensioni totali della cache). Ovviamente, parte di questo invecchiamento comporta potenziali condizioni di gara, specialmente se i callback del timer si verificano in modo asincrono.

risposta data 10.02.2018 - 17:35
fonte
1

Dici:

To me, it's a bad design as I'm changing the behaviour of my processors while they should be Stateless, but I do not known how to deal with that?

Crea qualcosa di apolide separando lo stato dalle azioni che si verificano sullo stato. Quindi si passa lo stato nel codice che esegue le azioni. Forse non hai separato le cose nel modo più pulito possibile? Invece di avere un Processor che contiene un Configuration e poi ha il suo metodo process() chiamato dopo aver impostato la configurazione, puoi farlo semplicemente avere solo un metodo process() (o renderlo una funzione libera se la tua lingua lo consente che), e passi in Configuration ?

Loading the configuration can be very long and does not change so often so I did not want to recreate a Processor each time I want to make it process.

Ci sono modi in cui puoi migliorare questo? Ad esempio, devi caricare l'intera configurazione ogni volta? È possibile che gran parte di essa venga copiata da un'istanza esistente e solo le parti che sono diverse vengano aggiornate? Se dovessi fornire i dettagli di cosa implica "caricare una configurazione" (in un'altra domanda), i lettori potrebbero avere suggerimenti su come migliorare le sue prestazioni. Potrebbe spesso essere usato% su% co_de essere serializzato su disco e quindi riletto in modo da non dover eseguire l'installazione ogni volta? Potrebbe Configurations essere generato da più Configurations di base o da altri pezzi per ridurre il sovraccarico di creazione di nuovi?

    
risposta data 10.02.2018 - 23:13
fonte

Leggi altre domande sui tag