delayed_job & Syck::DomainType error

Cześć

mam problem z wysyłaniem maili przy użyciu delayed_joba.

podobny problem opisany jest :
http://flexcoder.org/p/undefined-method-error-when-creating-delayedjob-workers-with-scriptdelayjob-44932

obiekt zapisany w tabeli delyed_job :

--- !ruby/struct:Delayed::PerformableMethod object: !ruby/ActiveRecord:User attributes: ....... method_name: :send_confirmation_instructions_without_delay args: []
backtrace

[code]{undefined method `send_confirmation_instructions_without_delay’ for #Syck::DomainType:0x00000009c87950

Syck::DomainType#send_confirmation_instructions_without_delay failed with NoMethodError: undefined method `send_confirmation_instructions_without_delay’ for #Syck::DomainType:0x00000009142e28 - 1 failed attempts[/code]
próbowałem solucji :

ale żadna nie daje pożądanego efektu ;/
liczę na szybką pomoc :wink:

używam RoR 3.0.7, Ruby 1.9.2p180, Bundler 1.0.18

Nie powiem Ci co jest przyczyną tego konkretnego problemu i jak ten konkretne błąd naprawić, ale powiem Ci dlaczego podejście jakiego używasz jest złe i że inne podejście rozwiąże Twoje problemy (no chyba, że się mylę to wtedy zwracam honor).

Używasz w kodzie metody delay, prawda? (w tym wypadku zdaje się user.delay.send_confirmation_instructions) Żeby ta piękna magia zadziałała cały obiekt usera musi zostać zserializowany i zapisany w bazie. Potem delayed_job pobiera taki zserializowany obiekt, deserializuje go i wykonuje na nim podaną metodę. Nie zawsze jednak to się powiedzie. Najprostszy przypadek: dj próbuje zdeserializować klasę, której nie zna (dzieje się tak gdy daemon dj nie posiada załadowanej klasy X, która została zserializowana w aplikacji).

[code=irb]> class Foo; attr :foo; def initialize; @foo = 1; end; end
nil

foo = Foo.new
#<Foo:0x00000102433368 @foo=1>
dump = YAML.dump(foo)
“— !ruby/object:Foo \nfoo: 1\n”
Object.send(:remove_const, :Foo)
Foo
YAML.load(dump).foo
NoMethodError: undefined method foo' for #<Syck::Object:0x00000102440fb8 @class="Foo", @ivars={"foo"=>1}> from (irb):36 from /Users/radarek/opt/bin/irb1.9:12:in'[/code]
Innym problemem jaki możesz napotkać to próba deserializacji obiektu starszej wersji klasy z załadowaną nowszą definicją (w przypadku dj łatwo o coś takiego gdy chcesz coś wykonać ze sporym opóźnieniem).

Moje osobiste zdanie na ten temat jest taki: twórz klasę per każde logiczne zadanie, które chcesz wykonać asynchronicznie (w tle) i przesyłaj do niej tylko prymitywne typy (liczny, stringi, tablice liczb itp), z którymi nigdy nie będziesz mieć problemów w kwestii serializacji.

Dla Twoje konkretnego przykładu byłoby to:

class ConfirmationInstructionsJob < Struct.new(:user_id) def perform user = User.find(user_id) UserMailer.deliver_confirmation_instructions(user) end end
Prócz tego, że to działa (i mnie nigdy w kwestiach technicznych nie zawiodło, w przeciwieństwie do delay i send_later) ma to dodatkową zaletę. W jednym miejscu ma się wszystkie brackgroundowe taski.