-
Notifications
You must be signed in to change notification settings - Fork 102
/
resque_mailer.rb
205 lines (169 loc) · 5.76 KB
/
resque_mailer.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
require 'resque_mailer/version'
require 'resque_mailer/serializers/pass_thru_serializer'
require 'resque_mailer/serializers/active_record_serializer'
require 'resque_mailer/symbolized_hash_with_indifferent_access'
module Resque
module Mailer
class << self
attr_accessor :default_queue_name, :default_queue_target, :current_env, :logger, :error_handler
attr_accessor :argument_serializer
attr_reader :excluded_environments
def excluded_environments=(envs)
@excluded_environments = [*envs].map { |e| e.to_sym }
end
def prepare_message(klass, action, *args)
msg = klass.send(:new)
msg.process(action, *args)
msg.message
end
def included(base)
base.extend(ClassMethods)
end
end
self.logger ||= (defined?(Rails) ? Rails.logger : nil)
self.default_queue_target = ::Resque
self.default_queue_name = "mailer"
self.excluded_environments = [:test]
self.argument_serializer = ::Resque::Mailer::Serializers::PassThruSerializer
module ClassMethods
def current_env
if defined?(Rails)
::Resque::Mailer.current_env || ::Rails.env
else
::Resque::Mailer.current_env
end
end
def method_missing(method_name, *args)
if action_methods.include?(method_name.to_s)
MessageDecoy.new(self, method_name, *args)
else
super
end
end
def perform(action, serialized_args)
begin
args = ::Resque::Mailer.argument_serializer.deserialize(serialized_args)
# Set hash as hash with indifferent access so mailer block syntax (needs symbols) works
if args.is_a?(Array)
args = args.each_with_object([]) do |arg, o|
o << (arg.is_a?(Hash) ? ::Resque::Mailer::SymbolizedHashWithIndifferentAccess.new(arg) : arg)
end
end
message = ::Resque::Mailer.prepare_message(self, action, *args)
if message.respond_to?(:deliver_now)
message.deliver_now
else
message.deliver
end
rescue Exception => ex
if Mailer.error_handler
Mailer.error_handler.call(self, message, ex, action, args)
else
if logger
logger.error "Unable to deliver email [#{action}]: #{ex}"
logger.error ex.backtrace.join("\n\t")
end
raise ex
end
end
end
def queue
@queue || ::Resque::Mailer.default_queue_name
end
def queue=(name)
@queue = name
end
def resque
::Resque::Mailer.default_queue_target
end
def excluded_environment?(name)
::Resque::Mailer.excluded_environments && ::Resque::Mailer.excluded_environments.include?(name.try(:to_sym))
end
def deliver?
true
end
end
class MessageDecoy
delegate :to_s, :to => :actual_message
def initialize(mailer_class, method_name, *args)
@mailer_class = mailer_class
@method_name = method_name
*@args = *args
@serialized_args = ::Resque::Mailer.argument_serializer.serialize(*args)
actual_message if environment_excluded?
end
def resque
::Resque::Mailer.default_queue_target
end
def current_env
if defined?(Rails)
::Resque::Mailer.current_env || ::Rails.env
else
::Resque::Mailer.current_env
end
end
def environment_excluded?
!ActionMailer::Base.perform_deliveries || excluded_environment?(current_env)
end
def excluded_environment?(name)
::Resque::Mailer.excluded_environments && ::Resque::Mailer.excluded_environments.include?(name.to_sym)
end
def actual_message
@actual_message ||= ::Resque::Mailer.prepare_message(@mailer_class, @method_name, *@args)
end
def deliver
return deliver! if environment_excluded?
if @mailer_class.deliver?
begin
resque.enqueue(@mailer_class, @method_name, @serialized_args)
rescue Errno::ECONNREFUSED, Redis::CannotConnectError
logger.error "Unable to connect to Redis; falling back to synchronous mail delivery" if logger
deliver!
end
end
end
alias_method :deliver_now, :deliver
def deliver_at(time)
return deliver! if environment_excluded?
unless resque.respond_to? :enqueue_at
raise "You need to install resque-scheduler to use deliver_at"
end
if @mailer_class.deliver?
resque.enqueue_at(time, @mailer_class, @method_name, @serialized_args)
end
end
def deliver_in(time)
return deliver! if environment_excluded?
unless resque.respond_to? :enqueue_in
raise "You need to install resque-scheduler to use deliver_in"
end
if @mailer_class.deliver?
resque.enqueue_in(time, @mailer_class, @method_name, @serialized_args)
end
end
def unschedule_delivery
unless resque.respond_to? :remove_delayed
raise "You need to install resque-scheduler to use unschedule_delivery"
end
resque.remove_delayed(@mailer_class, @method_name, @serialized_args)
end
def deliver!
if actual_message.respond_to?(:deliver_now)
actual_message.deliver_now
else
actual_message.deliver
end
end
alias_method :deliver_now!, :deliver!
def method_missing(method_name, *args)
actual_message.send(method_name, *args)
end
def respond_to?(method_name, *args)
super || actual_message.respond_to?(method_name, *args)
end
def logger
@mailer_class.logger
end
end
end
end