Неизменност и презареждащи се конфигурации

Моля, обърнете внимание: Въпреки че в този въпрос се споменава Java, мисля, че в основата си това е проблем с OOP/паралелност и вероятно може да бъде отговорен от всеки със значителен опит в програмирането.


Така че изграждам ConfigurationLoader, който ще чете Configuration POJO от отдалечена услуга и ще го направи достъпен чрез API. Няколко неща:

  • Веднага след като ConfigurationLoader бъде помолен за Configuration за първи път, фонова нишка (работник) ще пингва отдалечената услуга на всеки, да речем, 30 секунди, за актуализации и след това ще приложи тези актуализации към екземпляра Configuration; и
  • Ако Configuration е променен, фоновият работник ще бъде уведомен за промяната и ще изпрати „новия“ Configuration към отдалечената услуга;
  • Както ConfigurationLoader, така и Configuration трябва да са безопасни за нишки

Така че, когато си помисля за „безопасност на нишките“, първото нещо, за което се сещам, е неизменността, което ме води към отлични проекти като Неизменни. Проблемът е, че Configuration не може да бъде неизменен, защото трябва да можем да го променим от страна на клиента и след това да позволим на зареждащия механизъм да върне тези промени обратно към сървъра.

Следващата ми мисъл беше да опитам да направя както ConfigurationLoader, така и Configuration сингълтони, но проблемът е, че ConfigurationLoader отнема много аргументи, за да го инстанцира, и като този отличен отговор посочва, че сингълтън, който приема аргументи в конструкцията, не е истински сингълтън.

// Groovy pseudo-code
class Configuration {
    // Immutable? Singleton? Other?
}

class ConfigurationLoader {
    // private fields
    Configuration configuration

    ConfigurationLoader(int fizz, boolean buzz, Foo foo, List<Bar> bars) {
        super()

        this.fizz = fizz
        this.buzz = buzz;
        // etc.
    }

    Configuration loadConfiguration() {
        if(configuration == null) {
            // Create background worker that will constantly update
            // 'configuration'
        }
    }
}

Какви са моите опции тук? Как да създам и зареждащото устройство, и конфигурацията, за да бъдат безопасни за нишки, където конфигурацията може да се променя от страна на клиента (при поискване) или асинхронно от фонов работник нишка?


person smeeb    schedule 15.09.2015    source източник


Отговори (2)


Проблемът е, че конфигурацията не може да бъде неизменна, защото трябва да можем да я променим

Той все още може да бъде неизменен, просто създавате нов за всяка промяна ("copy-on-write").

Какви са ми опциите тук?

Първото нещо, за което трябва да помислите: Как искате да реагирате на промените в конфигурацията в едновременно изпълнявани задачи? По принцип имате три възможности:

Игнорирайте промените в конфигурацията, докато задачата не бъде изпълнена

т.е. някаква директория, в която вашите кодове записват файлове - завършете записа на текущия файл в текущата целева директория, поставете нови файлове в новата директория. Записването на няколко байта в /new/path/somefile няма да е добра идея, ако никога не сте създавали този файл. Вашият най-добър вариант за това вероятно е неизменен Configuration обект, който съхранявате в поле на вашия екземпляр на задача (т.е. при създаване на задача - в този случай можете също да направите това поле final за яснота). Това обикновено работи най-добре, ако вашият код е проектиран като колекция от изолирани малки задачи.

Плюсове: Конфигурацията никога не се променя в рамките на една задача, така че това е лесно да бъде безопасно и лесно за тестване.

Минуси: Актуализациите на конфигурацията никога не достигат до вече изпълнявани задачи.

Накарайте задачите си да проверяват за промени в конфигурацията

т.е. вашата задача редовно изпраща някои данни на имейл адрес. Имайте централно хранилище за вашата конфигурация (като във вашия псевдокод) и го извличайте отново в определен интервал (т.е. между събирането на данни и изпращането на пощата) от кода на вашата задача. Това обикновено работи най-добре за дълготрайни/постоянни задачи.

Плюсове: Конфигурацията може да се променя по време на изпълнение на задача, но все пак е донякъде лесно да се защитите - просто се уверете, че имате някаква бариера в паметта за четене на конфигурацията (направете своето лично configuration поле volatile, използвайте AtomicReference , пазете го с ключалка, каквото и да е).

Минуси: Кодът на задачата ще бъде по-труден за тестване от първия вариант. Стойностите на конфигурацията все още може да са остарели между проверките.

Сигнализирайте промените в конфигурацията на вашите задачи

По принцип вариант две, но обратното. Всеки път, когато конфигурацията се промени, прекъсвайте задачите си, обработвайте прекъсването като съобщение „конфигурацията се нуждае от актуализиране“, продължете/рестартирайте с нова конфигурация.

Плюсове: Стойностите на конфигурацията никога не са остарели.

Минуси: Това е най-трудното за правилно. Някои може дори да възразят, че не можете да разберете това правилно, защото прекъсването трябва да се използва само за аборт на задача. Има само много незначителни предимства (ако въобще) спрямо втората опция, ако поставите проверките за актуализиране на задачата си на правилните места. Не правете това, ако нямате основателна причина.

person duckstep    schedule 15.09.2015

Имате нужда от сингълтън, за да направите това, но вашият сингълтон не е неизменното нещо. Това е безопасното нещо. Направете вашия сингълтън (Конфигурация) да съдържа прост обект Properties или нещо подобно и защитете достъпа до него със синхронизация. Вашият Configuration Loader по някакъв начин знае за този Configuration singleton и функционира, за да зададе, при синхронизиране, нови екземпляри на обекта Properties, когато открие промяна.

Почти съм сигурен, че Apache Commons Configuration прави нещо подобно.

person Bob Kuhar    schedule 15.09.2015