Как я могу сделать потокобезопасный синглтон с Rails, как сохранить переменные моих классов в безопасности?
Я прочитал Является ли Rails shared-nothing или отдельные запросы могут обращаться к одним и тем же переменным среды выполнения? и они объясняют мою проблему:
Переменная класса может быть разделена между двумя запросами к моему rails srver, но где же решение!?
Как я могу реализовать безопасный синглтон между запросами?
class Foo
@@instances = []
end
Как я могу быть уверен, что экземпляры будут сброшены для каждого запроса HTTP?!
Правка:
Я нахожу " config.reload_classes_only_on_change = false " решение, но я не уверен, что это лучший вариант для выступления.
Каковы последствия этого варианта?
У меня есть исключение для проверки переменных безопасных классов:
class Test
def self.log
@test ||= false
puts @test
@test = true
end
end
class ApplicationController < ActionController::Base
def index
Test.log
Test.log
end
end
Если я запускаю этот код с действием перезагрузки (F5), я хочу читать "false" каждый раз в журнале сервера rails. Но по умолчанию это "ложь" только в первый раз.
Правка 2: На самом деле эта опция перезагружает класс, но не решает проблему параллелизма в потоке. Переменные классов сбрасываются, но они могут быть изменены другими нитка.
Как threadsafe классы переменных?
1 ответ:
Я использую request_store gem, он отлично работает.
Мой вариант использования-это добавление методов в класс модели пользователя, таких как current_user, их локаль, расположение и т. д., поскольку часто другие модели нуждаются в этой информации.
Я просто настраиваю текущего пользователя из моего контроллера приложений:
User.current = the_authenticated_user User.request = request
И в моем классе модели пользователя:
class User def self.current RequestStore.store[:current_user] end def self.current=(user) RequestStore.store[:current_user] = user end def self.request RequestStore.store[:current_request] end def self.request=(request) # stash the request so things like IP address and GEO-IP based location is available to other models RequestStore.store[:current_request] = request end def self.location # resolve the location just once per request RequestStore.store[:current_location] ||= self.request.try(:location) end end
Я не включаю опцию reload classes, так как это вызывает слишком много проблем, я видел несколько версий зависания классов вокруг. При использовании наследования моделей (т. е. STI) ленивая загрузка и / или динамическая загрузка классов часто нарушают порядок разрешения классов моделей. Необходимо использовать require_dependency в базовых и промежуточных классах моделей, чтобы обеспечить загрузку нижестоящих классов.
Мои настройки разработки зеркально отражают мои производственные настройки wrt class handling, что не удобно (требует перезагрузки сервера после изменения), но более удобно, чем гоняться за несуществующими ошибками. Драгоценный каменьrerun может мониторинг изменений файловой системы и перезагрузка сервера для вас, так что вы получите надежную обработку изменений в процессе разработки, хотя и медленнее, чем rails broken class reloading.
Конфигурация / среда / разработка.РБ:
# Rails class reloading is broken, anytime a class references another you get multiple # class instances for the same named class and that breaks everything. This is especially # important in Sequel as models resolve classes once. # So always cache classes (true) config.cache_classes = true # Always eager load so that all model classes are known and STI works config.eager_load = true
Q: Как threadsafe классы переменных?
A: никакие переменные не являются потокобезопасными, если они не защищены
synchronize
.С архитектурной точки зрения резьба по рельсам-пустая трата времени. Единственный способ, которым я смог получить истинную параллель производительность / параллелизм-это несколько процессов. Он также позволяет избежать блокировки и потоковых накладных расходов, которые просто не существуют при длительном выполнении процессов. Я тестировал параллельно интенсивные код процессора с использованием нитей с Рубином 2.x и вообще никакого параллелизма. С 1 процессом ruby на ядро я получил реальный параллелизм.
Я бы серьезно рассмотрел Thin с несколькими процессами, а затем решил, хотите ли вы использовать Thin+EventMachine для увеличения общей пропускной способности каждого процесса.