message 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Message
2
2
 
3
- https://travis-ci.org/xli/message.svg?branch=master
3
+ [![Build Status](https://travis-ci.org/xli/message.svg?branch=master)](https://travis-ci.org/xli/message)
4
+
4
5
 
5
6
  Message provides flexible & reliable background/asynchronous job processing mechanism on top of simple queue interface.
6
7
 
@@ -22,7 +23,7 @@ and you can easily swap in other queues later.
22
23
  ### Queuing jobs
23
24
 
24
25
 
25
- Inspired by delayed_job API, call .async.method(params) on any object and it will be processed in the background.
26
+ Call .async.method(params) on any object and it will be processed in the background.
26
27
 
27
28
  # without message
28
29
  @img.resize(36)
@@ -30,10 +31,22 @@ Inspired by delayed_job API, call .async.method(params) on any object and it wil
30
31
  # with message
31
32
  @img.async.resize(36)
32
33
 
33
- ### Start worker to process jobs
34
+ The above .async call will enqueue the job to a default job queue (Message.worker.default_job)
35
+
36
+ ### Start worker to process default job queue
34
37
 
35
38
  Message.worker.start
36
39
 
40
+ ### Named job queue
41
+
42
+ Queuing jobs into speicific queue named 'image-resize-queue':
43
+
44
+ @img.async('image-resize-queue').resize(36)
45
+
46
+ Start a worker to process queued jobs:
47
+
48
+ Message.worker('image-resize-queue').start
49
+
37
50
  ### Change to synchronize mode
38
51
 
39
52
  Message.worker.sync = true
@@ -48,93 +61,9 @@ For some environment or queue system (e.g. AWS SQS), you will need set an applic
48
61
 
49
62
  Message.worker.default_job = "app-name-#{Rails.env}-message-default"
50
63
 
51
- ## Job interface specification
52
-
53
- Job = a queue + message processor
54
-
55
- ### initialize a job
56
-
57
- job = Message.job('name') { |msg| ... process msg ... }
58
-
59
- ### enq(msg), alias: <<
60
-
61
- Queue up a message for processing:
62
-
63
- job << msg
64
-
65
- ### process(size=1)
66
-
67
- Process a message in queue by processor defined when initializing the job
68
-
69
- job.process
70
-
71
- Process multiple messages
72
-
73
- job.process(5)
74
-
75
- ## Job filters
76
-
77
- You can add job filter to add additional functions to enqueue and process job message
78
-
79
- Message.job.filter(filter_name) do |next_filter, job|
80
- lambda do |*args, &block|
81
- next_filter.call(*args, &block)
82
- end
83
- end
64
+ ### Change backend queue system
84
65
 
85
- Filters will be applied as the order initialized.
86
- Checkout all filters:
87
-
88
- Message.job.filters
89
-
90
- ### enq filter
91
-
92
- Message.job.filter(:enq) do |filter, job|
93
- lambda do |work|
94
- filter.call(work)
95
- end
96
- end
97
-
98
- ### process filter
99
-
100
- Message.job.filter(:process) do |filter, job|
101
- lambda do |size, &processor|
102
- filter.call(size) do |msg|
103
- processor.call(msg)
104
- end
105
- end
106
- end
107
-
108
- ## Queue adapters
109
-
110
- Change queue adapter to change different queue implementation. Default is a in memory queue for testing and development environments.
111
-
112
- ### Change adapter
66
+ By change queue adapter:
113
67
 
114
68
  Message.queue.adapter = :sqs
115
69
 
116
- ### Add a new adapter
117
-
118
- Message.queue.adapters[:sqs] = Message::SqsQueue
119
-
120
- ## Queue interface specification
121
-
122
- To hook up a new queue into Message.
123
-
124
- ### name
125
-
126
- Queue name.
127
-
128
- ### enq(msg), alias: <<
129
-
130
- Enqueue message, non-blocking.
131
-
132
- ### deq(size, &block)
133
-
134
- Dequeue message, non-blocking.
135
- It is up to Queue implementation when to delete the message in queue when deq got called with a block.
136
-
137
- ### size
138
-
139
- (Approximate) queue size.
140
-
@@ -0,0 +1,20 @@
1
+ require 'benchmark'
2
+ module Message
3
+ class Filters
4
+ class Benchmarking
5
+ def call(filter, job, action)
6
+ lambda do |msg|
7
+ return filter.call(msg) unless action == :process
8
+
9
+ ret = nil
10
+ Message.logger.info { "#{job.name}: processing one message"}
11
+ s = Benchmark.realtime do
12
+ ret = filter.call(msg)
13
+ end
14
+ Message.logger.info { "#{job.name}: processed in #{(1000 * s).to_i}ms" }
15
+ ret
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ module Message
2
+ class Filters
3
+ class ErrorHandling
4
+ attr_accessor :callback
5
+
6
+ def call(filter, job, action)
7
+ lambda do |msg|
8
+ begin
9
+ filter.call(msg)
10
+ rescue => e
11
+ job_name = job.name rescue 'unknown job(find job name failed)'
12
+ Message.logger.error {"#{action} #{job_name} message failed, #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"}
13
+ if self.callback
14
+ self.callback.call(e, msg, job, action)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ module Message
2
+ class Filters
3
+ class RetryOnError
4
+ attr_accessor :tries, :on, :sleep
5
+ def initialize
6
+ @tries = 3
7
+ @on = StandardError
8
+ @sleep = 0.001
9
+ end
10
+
11
+ def call(filter, _, _)
12
+ lambda do |arg|
13
+ @try = 0
14
+ begin
15
+ filter.call(arg)
16
+ rescue self.on => e
17
+ @try += 1
18
+ if @try < self.tries
19
+ Kernel.sleep self.sleep.to_f
20
+ retry
21
+ end
22
+ raise
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,66 +1,37 @@
1
- require 'benchmark'
1
+ require 'message/filters/error_handling'
2
+ require 'message/filters/benchmarking'
3
+ require 'message/filters/retry_on_error'
2
4
 
3
5
  module Message
4
6
  class Filters
5
- attr_reader :config
7
+ include Enumerable
8
+
9
+ attr_accessor :error_handling, :benchmarking, :retry_on_error
6
10
 
7
11
  def initialize
8
- @data = Hash.new{|h,k|h[k]=[]}
9
- @config = {
10
- :error_handling_callback => lambda {|type, job, msg, e| }
11
- }
12
- defaults.each do |t, m|
13
- self[t] << [m, method(m)]
14
- end
12
+ @data = []
13
+ @error_handling = ErrorHandling.new
14
+ @benchmarking = Benchmarking.new
15
+ @retry_on_error = RetryOnError.new
16
+ load(defaults)
15
17
  end
16
18
 
17
- def [](type)
18
- @data[type]
19
+ def <<(filter)
20
+ @data << filter
19
21
  end
20
22
 
21
- def defaults
22
- [
23
- [:process, :error_handling],
24
- [:enq, :error_handling],
25
- [:process, :benchmarking]
26
- ]
27
- end
28
-
29
- def error_handling(filter, job)
30
- lambda do |arg, &processor|
31
- type = processor ? :process : :enq
32
- log_error(type, job, (type == :enq ? arg : nil)) do
33
- if processor
34
- filter.call(arg) do |msg|
35
- log_error(type, job, msg) { processor.call(msg) }
36
- end
37
- else
38
- filter.call(arg)
39
- end
40
- end
23
+ def load(data)
24
+ data.each do |m|
25
+ @data << [m, send(m)]
41
26
  end
42
27
  end
43
28
 
44
- def benchmarking(filter, job)
45
- lambda do |size, &processor|
46
- filter.call(size) do |msg|
47
- ret = nil
48
- Message.logger.info { "#{job.name}: processing one message"}
49
- s = Benchmark.realtime do
50
- ret = processor.call(msg)
51
- end
52
- Message.logger.info { "#{job.name}: processed in #{(1000 * s).to_i}ms" }
53
- ret
54
- end
55
- end
29
+ def defaults
30
+ [:error_handling, :benchmarking, :retry_on_error]
56
31
  end
57
32
 
58
- private
59
- def log_error(type, job, msg, &block)
60
- block.call
61
- rescue => e
62
- Message.logger.error {"#{type} #{job.name} message failed, #{e.class}: #{e.message}\n#{e.backtrace.join("\n")}"}
63
- config[:error_handling_callback].call(type, job, msg, e)
33
+ def each(&block)
34
+ @data.each(&block)
64
35
  end
65
36
  end
66
37
  end
data/lib/message/job.rb CHANGED
@@ -7,8 +7,8 @@ module Message
7
7
  @filters ||= Filters.new
8
8
  end
9
9
 
10
- def filter(type, name, &block)
11
- filters[type] << [name, block]
10
+ def filter(name, &block)
11
+ filters << [name, block]
12
12
  end
13
13
 
14
14
  def reset
@@ -30,18 +30,23 @@ module Message
30
30
  end
31
31
 
32
32
  def enq(msg)
33
- chain(:enq, @queue.method(:enq)).call(msg)
33
+ chain(:enq, lambda {|msg| @queue.enq(msg)}).call(msg)
34
34
  end
35
35
  alias :<< :enq
36
36
 
37
37
  def process(size=1)
38
- chain(:process, @queue.method(:deq)).call(size, &@processor)
38
+ deq = lambda do |size|
39
+ @queue.deq(size) do |msg|
40
+ chain(:process, @processor).call(msg)
41
+ end
42
+ end
43
+ chain(:deq, deq).call(size)
39
44
  end
40
45
 
41
46
  private
42
- def chain(type, base)
43
- Job.filters[type].reverse.inject(base) do |m, f|
44
- f[1].call(m, self)
47
+ def chain(action, base)
48
+ Job.filters.to_a.reverse.inject(base) do |m, f|
49
+ f[1].call(m, self, action)
45
50
  end
46
51
  end
47
52
  end
data/lib/message/q.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  require 'message/in_memory_queue'
2
2
  module Message
3
+ class AdapterNotFoundError < StandardError
4
+ end
5
+
3
6
  module Q
4
7
  module_function
5
8
  def init(name)
@@ -15,6 +18,10 @@ module Message
15
18
  end
16
19
 
17
20
  def adapter=(name)
21
+ name = name.to_sym
22
+ unless adapters.has_key?(name)
23
+ raise AdapterNotFoundError, "Could not find adapter named #{name.inspect}"
24
+ end
18
25
  @adapter = name
19
26
  end
20
27
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: message
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
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: 2014-09-09 00:00:00.000000000 Z
12
+ date: 2014-09-13 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! 'Message provides flexible & reliable background/asynchronous job processing
15
15
  mechanism on top of simple queue interface.
@@ -31,6 +31,9 @@ extensions: []
31
31
  extra_rdoc_files: []
32
32
  files:
33
33
  - README.md
34
+ - lib/message/filters/benchmarking.rb
35
+ - lib/message/filters/error_handling.rb
36
+ - lib/message/filters/retry_on_error.rb
34
37
  - lib/message/filters.rb
35
38
  - lib/message/in_memory_queue.rb
36
39
  - lib/message/job.rb