sad 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile CHANGED
@@ -3,6 +3,8 @@ source "http://ruby.taobao.org"
3
3
  gem 'jeweler'
4
4
 
5
5
  gem 'activesupport'
6
+ gem 'eventmachine'
6
7
  gem 'em-hiredis'
7
8
  gem 'daemons'
8
- gem "json"
9
+ gem "json"
10
+ gem 'pry'
data/Gemfile.lock CHANGED
@@ -4,9 +4,11 @@ GEM
4
4
  activesupport (3.2.13)
5
5
  i18n (= 0.6.1)
6
6
  multi_json (~> 1.0)
7
+ coderay (1.0.9)
7
8
  daemons (1.1.9)
8
9
  em-hiredis (0.2.1)
9
10
  hiredis (~> 0.4.0)
11
+ eventmachine (1.0.3)
10
12
  git (1.2.5)
11
13
  hiredis (0.4.5)
12
14
  i18n (0.6.1)
@@ -16,10 +18,16 @@ GEM
16
18
  rake
17
19
  rdoc
18
20
  json (1.7.7)
21
+ method_source (0.8.1)
19
22
  multi_json (1.7.2)
23
+ pry (0.9.12)
24
+ coderay (~> 1.0.5)
25
+ method_source (~> 0.8)
26
+ slop (~> 3.4)
20
27
  rake (10.0.4)
21
28
  rdoc (4.0.0)
22
29
  json (~> 1.4)
30
+ slop (3.4.4)
23
31
 
24
32
  PLATFORMS
25
33
  ruby
@@ -28,5 +36,7 @@ DEPENDENCIES
28
36
  activesupport
29
37
  daemons
30
38
  em-hiredis
39
+ eventmachine
31
40
  jeweler
32
41
  json
42
+ pry
data/README.md CHANGED
@@ -41,7 +41,6 @@ EM.run{
41
41
 
42
42
  两个运行环境都要有SadJob这个测试类的定义存在
43
43
 
44
- --------
45
44
 
46
45
  ## 在项目中使用
47
46
 
@@ -90,6 +89,40 @@ Sad::Config.namespace = 'MyBackgroundJobQueue'
90
89
  6181 ?? S 0:02.61 Sad-2
91
90
  6522 s002 R+ 0:00.00 grep Sad
92
91
 
92
+
93
+ ## 测试
94
+
95
+ 启动一个队列
96
+
97
+ ```sh
98
+ bundle exec rake sad:restart COUNT=1 QUEUE=MySadJob DIR=./tmp/pids
99
+ ```
100
+
101
+ 执行最简单的测试
102
+
103
+ ```sh
104
+ bundle exec ruby ./test/test_sad.rb
105
+ ```
106
+
107
+ 执行异常任务测试,异常是指Klass.perform函数执行时出现异常,如果是异步任务,没办法知道异常,因为执行完perform后,代码运行环境已经脱离sad了,需要人工自己处理.
108
+
109
+ 当Klass.perform出错时,会延时重试,重试三次后,如果还有错误,则放弃该任务.
110
+
111
+ ```sh
112
+ bundle exec ruby ./test/test_perform_with_exception.rb
113
+ ```
114
+
115
+ 在异步模式的代码中,异常如果被抛给top level的运行时的话,则代码无法控制,所以有异常的时候一定要捕获到,写在类似errback的回调中,对于Sad的重试,自动重试只能保证perform执行没问题,如果在callback中出错,则需要用户手工将该任务重新enqueue来实现重试的机制。
116
+
117
+ ## 任务配置
118
+
119
+ ```ruby
120
+ SadJob.enqueue(1,2,3,4,5){|payload|
121
+ # delay -> 当sad进程得到该任务时并不立即执行,而是延迟多干秒后执行
122
+ payload.sad_args['delay'] = 5
123
+ }
124
+ ```
125
+
93
126
  ## Contributing to sad
94
127
 
95
128
  * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
data/Rakefile CHANGED
@@ -43,3 +43,6 @@ Rake::RDocTask.new do |rdoc|
43
43
  rdoc.rdoc_files.include('README*')
44
44
  rdoc.rdoc_files.include('lib/**/*.rb')
45
45
  end
46
+
47
+ require File.join(File.dirname(__FILE__), 'lib', 'sad')
48
+ require File.join(File.dirname(__FILE__), 'lib', 'sad', 'tasks')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.0
1
+ 1.4.0
data/lib/sad/config.rb CHANGED
@@ -9,6 +9,10 @@ module Sad
9
9
  @_namespace || 'SadQueue'
10
10
  end
11
11
 
12
+ def queue(q)
13
+ [Sad::Config.namespace, q].join ':'
14
+ end
15
+
12
16
  def redis=(uri)
13
17
  @_redis_url = uri
14
18
  end
@@ -16,6 +20,22 @@ module Sad
16
20
  def redis
17
21
  @_redis ||= EM::Hiredis.connect(@_redis_url)
18
22
  end
23
+
24
+ def interval=(int)
25
+ @_interval = int.to_i
26
+ end
27
+
28
+ def interval
29
+ @_interval ||= 3
30
+ end
31
+
32
+ def max_retry=(int)
33
+ @_max_retry = int.to_i
34
+ end
35
+
36
+ def max_retry
37
+ @_max_retry ||= 3
38
+ end
19
39
  end
20
40
  end
21
41
  end
data/lib/sad/payload.rb CHANGED
@@ -1,22 +1,55 @@
1
+ require "json"
2
+
1
3
  module Sad
2
4
  class Payload
3
- attr_accessor :klass, :args
5
+ attr_accessor :klass, :args, :sad_args
4
6
 
5
- def initialize(klass, args)
7
+ def initialize(klass, args = [], sad_args = {})
6
8
  @klass = klass
7
9
  @args = args
10
+ @sad_args = {
11
+ 'retry' => 0,
12
+ 'delay' => 0
13
+ }.update(sad_args)
8
14
  end
9
15
 
10
16
  def encode
11
17
  {
12
18
  'klass' => @klass,
13
- 'args' => @args
19
+ 'args' => @args,
20
+ 'sad_args' => @sad_args
14
21
  }.to_json
15
22
  end
16
23
 
24
+ # 执行任务
25
+ # 当执行任务的perform出错时
26
+ # 重试1至::Sad::Config.max_retry次
27
+ # 每次重试时,延迟重试次数*::Sad::Config.interval的时长后,再enqueue
28
+ def perform
29
+ begin
30
+ @klass.constantize.send :perform, *@args
31
+ rescue Exception => e
32
+ if self.sad_args['retry'] and (self.sad_args['retry'].to_i < ::Sad::Config.max_retry)
33
+ self.sad_args['retry'] = self.sad_args['retry'].to_i + 1
34
+ self.sad_args['delay'] = ::Sad::Config.interval * self.sad_args['retry']
35
+ self.enqueue
36
+ else
37
+ STDERR.puts "Payload perform error for #{self.sad_args['retry']} retrys:\n#{self.inspect}"
38
+ end
39
+ end
40
+ end
41
+
42
+ def enqueue
43
+ ::Sad::Config.redis.rpush(self.sad_args['queue'], self.encode)
44
+ end
45
+
17
46
  def self.decode(json)
18
47
  h = JSON.parse(json)
19
- self.new(h['klass'], h['args'])
48
+ if h['sad_args'] or h['sad_args'] != ''
49
+ self.new(h['klass'], h['args'], h['sad_args'])
50
+ else
51
+ self.new(h['klass'], h['args'])
52
+ end
20
53
  end
21
54
  end
22
55
  end
data/lib/sad/server.rb CHANGED
@@ -4,7 +4,7 @@ module Sad
4
4
  def run(queue)
5
5
  @_shutdown = false
6
6
  register_signal
7
- fetch([Sad::Config.namespace, queue].join ':')
7
+ fetch(Sad::Config.queue(queue))
8
8
  end
9
9
 
10
10
  def fetch(queue)
@@ -13,17 +13,34 @@ module Sad
13
13
  if data
14
14
  STDOUT.puts '-'*15 + data.inspect + '-'*15
15
15
  payload = Payload.decode(data)
16
- EM.defer{perform(payload.klass, payload.args)}
16
+ payload_call(payload)
17
17
  end
18
- fetch(queue) unless shutdown?
18
+ fetch_with_interval(queue)
19
19
  }
20
20
  request.errback{
21
+ STDERR.puts 'error with redis request.'
22
+ fetch_with_interval(queue)
23
+ }
24
+ end
25
+
26
+ def fetch_with_interval(queue)
27
+ EM.add_timer(::Sad::Config.interval){
21
28
  fetch(queue) unless shutdown?
22
29
  }
23
30
  end
24
31
 
25
- def perform(klass, args)
26
- klass.constantize.send :perform, *args
32
+ def payload_call(payload)
33
+ # 如果该任务有延时执行要求,
34
+ # 则在定时器执行时将其延时的key删掉,
35
+ # 再重新入队
36
+ if payload.sad_args['delay'] and payload.sad_args['delay'] != '' and payload.sad_args['delay'] != 0
37
+ EM.add_timer(payload.sad_args['delay'].to_i){
38
+ payload.sad_args.delete('delay')
39
+ payload.enqueue
40
+ }
41
+ else
42
+ payload.perform
43
+ end
27
44
  end
28
45
 
29
46
  def register_signal
@@ -43,6 +60,7 @@ module Sad
43
60
 
44
61
  def shutdown
45
62
  @_shutdown = true
63
+ EM.stop
46
64
  end
47
65
  end
48
66
  end
data/lib/sad/worker.rb CHANGED
@@ -6,12 +6,14 @@ module Sad
6
6
  else
7
7
  nil
8
8
  end
9
- [Sad::Config.namespace, name].join ':'
9
+ Sad::Config.queue(name)
10
10
  end
11
11
 
12
12
  def enqueue(*args)
13
13
  payload = ::Sad::Payload.new(self.to_s, args)
14
- ::Sad::Config.redis.rpush(queue_name, payload.encode)
14
+ payload.sad_args['queue'] = queue_name
15
+ yield payload if block_given?
16
+ payload.enqueue
15
17
  end
16
18
  end
17
19
  end
data/sad.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "sad"
8
- s.version = "1.3.0"
8
+ s.version = "1.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["\u{5d14}\u{5ce5}"]
12
- s.date = "2013-04-26"
12
+ s.date = "2013-04-27"
13
13
  s.description = "a simple em baseed background job worker."
14
14
  s.email = "zheng.cuizh@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
34
34
  "lib/tasks/sad.rake",
35
35
  "sad.gemspec",
36
36
  "test/helper.rb",
37
+ "test/test_perform_with_exception.rb",
37
38
  "test/test_sad.rb"
38
39
  ]
39
40
  s.homepage = "http://github.com/charlescui/sad"
@@ -48,22 +49,28 @@ Gem::Specification.new do |s|
48
49
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
50
  s.add_runtime_dependency(%q<jeweler>, [">= 0"])
50
51
  s.add_runtime_dependency(%q<activesupport>, [">= 0"])
52
+ s.add_runtime_dependency(%q<eventmachine>, [">= 0"])
51
53
  s.add_runtime_dependency(%q<em-hiredis>, [">= 0"])
52
54
  s.add_runtime_dependency(%q<daemons>, [">= 0"])
53
55
  s.add_runtime_dependency(%q<json>, [">= 0"])
56
+ s.add_runtime_dependency(%q<pry>, [">= 0"])
54
57
  else
55
58
  s.add_dependency(%q<jeweler>, [">= 0"])
56
59
  s.add_dependency(%q<activesupport>, [">= 0"])
60
+ s.add_dependency(%q<eventmachine>, [">= 0"])
57
61
  s.add_dependency(%q<em-hiredis>, [">= 0"])
58
62
  s.add_dependency(%q<daemons>, [">= 0"])
59
63
  s.add_dependency(%q<json>, [">= 0"])
64
+ s.add_dependency(%q<pry>, [">= 0"])
60
65
  end
61
66
  else
62
67
  s.add_dependency(%q<jeweler>, [">= 0"])
63
68
  s.add_dependency(%q<activesupport>, [">= 0"])
69
+ s.add_dependency(%q<eventmachine>, [">= 0"])
64
70
  s.add_dependency(%q<em-hiredis>, [">= 0"])
65
71
  s.add_dependency(%q<daemons>, [">= 0"])
66
72
  s.add_dependency(%q<json>, [">= 0"])
73
+ s.add_dependency(%q<pry>, [">= 0"])
67
74
  end
68
75
  end
69
76
 
@@ -0,0 +1,20 @@
1
+ $:.unshift(File.dirname __FILE__)
2
+ require 'helper'
3
+
4
+ class SadJob
5
+ extend ::Sad::Worker
6
+
7
+ def self.queue
8
+ 'MySadJob'
9
+ end
10
+
11
+ def self.perform(*args)
12
+ raise RuntimeError, 'Error for test!!!!'
13
+ end
14
+ end
15
+
16
+ EM.run {
17
+ EM::PeriodicTimer.new(3){
18
+ SadJob.enqueue('this is some args', {:hello => 'code'})
19
+ }
20
+ }
data/test/test_sad.rb CHANGED
@@ -1,3 +1,4 @@
1
+ $:.unshift(File.dirname __FILE__)
1
2
  require 'helper'
2
3
 
3
4
  class SadJob
@@ -13,6 +14,8 @@ class SadJob
13
14
  end
14
15
  end
15
16
 
16
- EM::PeriodicTimer.new(3){
17
- SadJob.enqueue('this is some args', {:hello => 'code'})
18
- }
17
+ EM.run{
18
+ EM::PeriodicTimer.new(3){
19
+ SadJob.enqueue('this is some args', {:hello => 'code'})
20
+ }
21
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sad
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-26 00:00:00.000000000 Z
12
+ date: 2013-04-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: jeweler
@@ -43,6 +43,22 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: eventmachine
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
46
62
  - !ruby/object:Gem::Dependency
47
63
  name: em-hiredis
48
64
  requirement: !ruby/object:Gem::Requirement
@@ -91,6 +107,22 @@ dependencies:
91
107
  - - ! '>='
92
108
  - !ruby/object:Gem::Version
93
109
  version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: pry
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
94
126
  description: a simple em baseed background job worker.
95
127
  email: zheng.cuizh@gmail.com
96
128
  executables: []
@@ -116,6 +148,7 @@ files:
116
148
  - lib/tasks/sad.rake
117
149
  - sad.gemspec
118
150
  - test/helper.rb
151
+ - test/test_perform_with_exception.rb
119
152
  - test/test_sad.rb
120
153
  homepage: http://github.com/charlescui/sad
121
154
  licenses:
@@ -132,7 +165,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
132
165
  version: '0'
133
166
  segments:
134
167
  - 0
135
- hash: 3515885531508128638
168
+ hash: -1386435798103601784
136
169
  required_rubygems_version: !ruby/object:Gem::Requirement
137
170
  none: false
138
171
  requirements: