Skip to content

Commit 1fadecb

Browse files
committed
Merge branch '1-x-stable'
Conflicts: examples/monit/resque.monit lib/resque/helpers.rb test/worker_test.rb
2 parents 87af931 + d76dce7 commit 1fadecb

File tree

17 files changed

+449
-23
lines changed

17 files changed

+449
-23
lines changed

HISTORY.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
## 1.21.0 (2012-07-02)
2+
3+
* Add a flag to make sure failure hooks are only ran once (jakemack, #546)
4+
* Support updated MultiJSON API (@twinturbo)
5+
* Fix worker logging in monit example config (@twinturbo)
6+
* loosen dependency of redis-namespace to 1.x, support for redis-rb 3.0.x
7+
* change '%' to '$' in the 'stop program' command for monit
8+
* UTF8 sanitize exception messages when there's a failure (@brianmario, #507)
9+
* don't share a redis connection between parent and child (@jsanders, #588)
10+
111
## 1.20.0 (2012-02-17)
212

313
* Fixed demos for ruby 1.9 (@BMorearty, #445)

examples/monit/resque.monit

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
check process resque_worker_QUEUE
22
with pidfile /data/APP_NAME/current/tmp/pids/resque_worker_QUEUE.pid
33
start program = "/usr/bin/env HOME=/home/user RACK_ENV=production PATH=/usr/local/bin:/usr/local/ruby/bin:/usr/bin:/bin:$PATH /bin/sh -l -c 'cd /data/APP_NAME/current; nohup bundle exec rake environment resque:work RAILS_ENV=production QUEUE=queue_name VERBOSE=1 PIDFILE=tmp/pids/resque_worker_QUEUE.pid >> log/resque_worker_QUEUE.log 2>&1'" as uid deploy and gid deploy
4-
stop program = "/bin/sh -c 'cd /data/APP_NAME/current && kill -9 %(cat tmp/pids/resque_worker_QUEUE.pid) && rm -f tmp/pids/resque_worker_QUEUE.pid; exit 0;'"
4+
stop program = "/bin/sh -c 'cd /data/APP_NAME/current && kill -9 $(cat tmp/pids/resque_worker_QUEUE.pid) && rm -f tmp/pids/resque_worker_QUEUE.pid; exit 0;'"
55
if totalmem is greater than 300 MB for 10 cycles then restart # eating up memory?
6-
group resque_workers
6+
group resque_workers

lib/resque.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
require 'resque/coder'
1818
require 'resque/multi_json_coder'
1919

20+
require 'resque/vendor/utf8_util'
21+
2022
module Resque
2123
include Helpers
2224
extend self

lib/resque/errors.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@ class NoClassError < RuntimeError; end
77

88
# Raised when a worker was killed while processing a job.
99
class DirtyExit < RuntimeError; end
10+
11+
# Raised when child process is TERM'd so job can rescue this to do shutdown work.
12+
class TermException < SignalException; end
1013
end

lib/resque/failure/redis.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def save
88
:failed_at => Time.now.strftime("%Y/%m/%d %H:%M:%S %Z"),
99
:payload => payload,
1010
:exception => exception.class.to_s,
11-
:error => exception.to_s,
11+
:error => UTF8Util.clean(exception.to_s),
1212
:backtrace => filter_backtrace(Array(exception.backtrace)),
1313
:worker => worker.to_s,
1414
:queue => queue

lib/resque/job.rb

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class Job
3232
def initialize(queue, payload)
3333
@queue = queue
3434
@payload = payload
35+
@failure_hooks_ran = false
3536
end
3637

3738
# Creates a job by placing it on a queue. Expects a string queue
@@ -43,7 +44,9 @@ def self.create(queue, klass, *args)
4344
Resque.validate(klass, queue)
4445

4546
if Resque.inline?
46-
constantize(klass).perform(*decode(encode(args)))
47+
# Instantiating a Resque::Job and calling perform on it so callbacks run
48+
# decode(encode(args)) to ensure that args are normalized in the same manner as a non-inline job
49+
new(:inline, {'class' => klass, 'args' => decode(encode(args))}).perform
4750
else
4851
Resque.push(queue, :class => klass.to_s, :args => args)
4952
end
@@ -210,14 +213,17 @@ def after_hooks
210213
@after_hooks ||= Plugin.after_hooks(payload_class)
211214
end
212215

213-
def failure_hooks
216+
def failure_hooks
214217
@failure_hooks ||= Plugin.failure_hooks(payload_class)
215218
end
216-
219+
217220
def run_failure_hooks(exception)
218-
job_args = args || []
219-
failure_hooks.each { |hook| payload_class.send(hook, exception, *job_args) }
221+
begin
222+
job_args = args || []
223+
failure_hooks.each { |hook| payload_class.send(hook, exception, *job_args) } unless @failure_hooks_ran
224+
ensure
225+
@failure_hooks_ran = true
226+
end
220227
end
221-
222228
end
223229
end

lib/resque/tasks.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
worker = Resque::Worker.new(*queues)
1515
worker.verbose = ENV['LOGGING'] || ENV['VERBOSE']
1616
worker.very_verbose = ENV['VVERBOSE']
17+
worker.term_timeout = ENV['RESQUE_TERM_TIMEOUT'] || 4.0
18+
worker.term_child = ENV['TERM_CHILD']
1719
rescue Resque::NoQueueError
1820
abort "set QUEUE env var, e.g. $ QUEUE=critical,high rake resque:work"
1921
end

lib/resque/vendor/utf8_util.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module UTF8Util
2+
# use '?' intsead of the unicode replace char, since that is 3 bytes
3+
# and can increase the string size if it's done a lot
4+
REPLACEMENT_CHAR = "?"
5+
6+
# Replace invalid UTF-8 character sequences with a replacement character
7+
#
8+
# Returns self as valid UTF-8.
9+
def self.clean!(str)
10+
raise NotImplementedError
11+
end
12+
13+
# Replace invalid UTF-8 character sequences with a replacement character
14+
#
15+
# Returns a copy of this String as valid UTF-8.
16+
def self.clean(str)
17+
clean!(str.dup)
18+
end
19+
20+
end
21+
22+
if RUBY_VERSION <= '1.9'
23+
require 'resque/vendor/utf8_util/utf8_util_18'
24+
else
25+
require 'resque/vendor/utf8_util/utf8_util_19'
26+
end
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
require 'strscan'
2+
3+
module UTF8Util
4+
HIGH_BIT_RANGE = /[\x80-\xff]/
5+
6+
# Check if this String is valid UTF-8
7+
#
8+
# Returns true or false.
9+
def self.valid?(str)
10+
sc = StringScanner.new(str)
11+
12+
while sc.skip_until(HIGH_BIT_RANGE)
13+
sc.pos -= 1
14+
15+
if !sequence_length(sc)
16+
return false
17+
end
18+
end
19+
20+
true
21+
end
22+
23+
# Replace invalid UTF-8 character sequences with a replacement character
24+
#
25+
# Returns self as valid UTF-8.
26+
def self.clean!(str)
27+
sc = StringScanner.new(str)
28+
while sc.skip_until(HIGH_BIT_RANGE)
29+
pos = sc.pos = sc.pos-1
30+
31+
if !sequence_length(sc)
32+
str[pos] = REPLACEMENT_CHAR
33+
end
34+
end
35+
36+
str
37+
end
38+
39+
# Validate the UTF-8 sequence at the current scanner position.
40+
#
41+
# scanner - StringScanner instance so we can advance the pointer as we verify.
42+
#
43+
# Returns The length in bytes of this UTF-8 sequence, false if invalid.
44+
def self.sequence_length(scanner)
45+
leader = scanner.get_byte[0]
46+
47+
if (leader >> 5) == 0x6
48+
if check_next_sequence(scanner)
49+
return 2
50+
else
51+
scanner.pos -= 1
52+
end
53+
elsif (leader >> 4) == 0x0e
54+
if check_next_sequence(scanner)
55+
if check_next_sequence(scanner)
56+
return 3
57+
else
58+
scanner.pos -= 2
59+
end
60+
else
61+
scanner.pos -= 1
62+
end
63+
elsif (leader >> 3) == 0x1e
64+
if check_next_sequence(scanner)
65+
if check_next_sequence(scanner)
66+
if check_next_sequence(scanner)
67+
return 4
68+
else
69+
scanner.pos -= 3
70+
end
71+
else
72+
scanner.pos -= 2
73+
end
74+
else
75+
scanner.pos -= 1
76+
end
77+
end
78+
79+
false
80+
end
81+
82+
private
83+
84+
# Read another byte off the scanner oving the scan position forward one place
85+
#
86+
# Returns nothing.
87+
def self.check_next_sequence(scanner)
88+
byte = scanner.get_byte[0]
89+
(byte >> 6) == 0x2
90+
end
91+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module UTF8Util
2+
def self.clean!(str)
3+
str.force_encoding("binary").encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => REPLACEMENT_CHAR)
4+
end
5+
end

0 commit comments

Comments
 (0)