Mam poważny problem z wielowątkowością.
Feature powinno wyglądać tak:
Jest sobie baza danych, którą co jakiś czasz przegląda automatyczny wątek (niezależnie od użytkowników) i modyfikuje jej dane.
Moja kulawa i sztukowana implementacja wygląda tak:
Jest sobie model (nazwijmy go Host), jest sobie też klasa HostsObserver (dziedziczy po ActiveRecord::Observer), która służy do uruchomienia wątku, który przegląda bazę.
W tym wątku jest wywołanie:
hosts = Host.find(:all)
Potem wszystko jest ładnie przetwarzane i cacy.
Niestety cacy jest tylko do momentu jakiejkolwiek próby odwołania do db (z innego miejsca np. przez wyświetlenia indeksu hostów przez kontroler).
Po złapaniu wyjątku dostaję taki komunikat:
A copy of HostsObserver has been removed from the module tree but is still active!
Próbowałem używać muteksy, monitory, Thread.critical i nic, dalej to samo.
Mam nadzieję, że ktoś z Was będzie miał jakiś pomysł, jak rozwiązać ten problem.
Przynajmniej chciałbym wiedzieć czemu usuwana jest instancja HostsObserver.
Coś kojarzę ten komunikat, spróbuj w klasie dodać linijkę “unloadable”, np.:
class Host < ActiveRecord::Observer
unloadable
...
end
To nie jest najlepsze rozwiązanie (nie wiem, czy ta metoda nie jest już “deprecated”) ale jeśli zadziała to może będzie wiadomo o co chodzi :-).
class HostsObserver < ActiveRecord::Observer
observe :host
def initialize
super
Thread.new do
while 1 do
begin
updateServices
rescue Exception => err
puts err.message
end
sleep (3) #nie pytaj czemu w sekundach
end
end
end
def updateServices
hosts = Host.find(:all) # jeśli tego niema to jest ok, ale być musi
bla bla bla, zabawy z hostami (zakomentowałem, więc to nie one powodują problem)
end
end[/code]
Chodzi mi tylko o to, żeby się bezproblemowo odwoływać do db.
Dodam, że takie sztuczki (jak wyżej) działały bezproblemowo w Rails 2.2.2, prowdopodobnie w Rails 2.3.2 coś się zmieniło i bardzo miło by było wiedzieć co.
//EDIT:
Jak nie kijem, to pałą - zamiast obserwatora użyję tego: BackgrounDRb.
Byle tylko się nie krzaczyło, bo mam już na czole odbitą klawiaturę
BackgrounDRb jest dobry jeśli masz długo wykonujące się skrypty odpalane przez jakieś wydarzenie pochodzące z aplikacji Rails (np. user klika w link).
Ty napisałeś “co jakiś czas” dlatego zapytam: dlaczego po prostu nie napiszesz skryptu który będzie robił to co potrzeba, umieścisz go w cron’ie który będzie go odpalał co jakiś czas np. przez script/runner ?
Wątki i BackgrouDRb to tutaj overkill (przynajmniej na tyle na ile opisałeś swój problem).
Jeśli faktycznie potrzebujesz czegoś co odpali długo działającą metodę po jakiejś akcji w Rails to jest jeszcze Spawn Najlepiej napisz co dokładnie próbujesz zrobić
Myślę, że BackgrounDRb będzie ok, ponieważ ma schedulera i co najważniejsze już zacząłem pisać.
//EDIT:
Zrobiłem - Oczywiście dobre rozwiązanie jest zawsze najprostsze - skrypt uruchamiany przez script/runner, działa wspaniale (do tej pory).
Nie trzeba było żadnych obserwatorów, barckground workerów, spawnów, ani innego kombinowania. (tylko czemu ja zawsze muszę pchać się w najdłuższą drogę?)