larva 0.1.0 → 0.3.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +14 -0
- data/CHANGELOG +7 -1
- data/README.md +61 -2
- data/lib/larva.rb +2 -0
- data/lib/larva/processor.rb +24 -0
- data/lib/larva/version.rb +1 -1
- data/lib/larva/worker_pool.rb +42 -0
- data/test/processor_test.rb +54 -0
- data/test/worker_pool_test.rb +38 -0
- metadata +8 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cbf84efda642aa79d413f133e1b7f27db278bec6
|
4
|
+
data.tar.gz: 88f947616c14e531fee42dc00fbd419372303bdb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1f4c8d39c1da9883535dc5b11f152e70a53c09906b6f4e29530514aa63dccd41c1d66f0ef540182d689a806d291c1a0b5b544be7d66d496281109043acdf795
|
7
|
+
data.tar.gz: 78624d5307e979b1bab7bf2d048cb14359d46a6147f2f484d6ec5c23b0146ac5fdf28b585ade020bd83feaca2969cfc575abe6f9ae48e0a82ceada5c6697c6dd
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
rvm:
|
4
|
+
- 1.9.3
|
5
|
+
- 2.0.0
|
6
|
+
- rbx-2.1.1
|
7
|
+
script:
|
8
|
+
- bundle exec rake test:local
|
9
|
+
#addons:
|
10
|
+
# code_climate:
|
11
|
+
# repo_token: 88dd239bc2e0010742a42a4e0234b4decd19b46d0e9d3408d8b1fe0f96dd8fc1
|
12
|
+
matrix:
|
13
|
+
allow_failures:
|
14
|
+
- rvm: rbx-2.1.1
|
data/CHANGELOG
CHANGED
data/README.md
CHANGED
@@ -18,17 +18,76 @@ And then execute:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
+
Larva provides you with listeners, processors and a worker pool to build an application that listens and responds to Propono messages.
|
22
|
+
|
23
|
+
Here is a sample application. This forms the basis of a rake task for most Meducation daemons.
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require 'larva'
|
27
|
+
|
28
|
+
# Setup Config for Filum and Propono
|
29
|
+
|
30
|
+
class MyProcessor < Larva::Processor
|
31
|
+
def process(message)
|
32
|
+
if entity == "comment" && action == "created"
|
33
|
+
# Do something...
|
34
|
+
else
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
processors = {my_topic: MyProcessor}
|
41
|
+
Larva::WorkerPool.start(processors, "queue-suffix")
|
42
|
+
|
43
|
+
```
|
44
|
+
|
21
45
|
### Listeners
|
22
46
|
|
23
47
|
Larva Listeners provide an easy way of listening to a Propono topic and processing the message, complete with lots of logging through Filum.
|
24
48
|
|
49
|
+
```ruby
|
50
|
+
Larva::Listener.listen(:my_topic, processor, "queue_suffix")
|
51
|
+
```
|
52
|
+
|
53
|
+
This will listen for messages on :my_topic and pass them to `processor.process`. It will log what is happening via Filum.
|
54
|
+
|
55
|
+
### Processors
|
56
|
+
|
57
|
+
Processors are used by listeners to handle the messages that are received. You are expected to subclass `Lavar::Processor` and implement `process`.
|
58
|
+
|
59
|
+
Processors expect you to have an `entity` and `action` fields in your messages.
|
60
|
+
|
61
|
+
For example:
|
62
|
+
|
25
63
|
```ruby
|
26
64
|
class MyProcessor
|
27
|
-
def
|
65
|
+
def process(message)
|
66
|
+
if entity == "comment" && action == "created"
|
67
|
+
# Do something...
|
68
|
+
else
|
69
|
+
false
|
70
|
+
end
|
28
71
|
end
|
29
72
|
end
|
73
|
+
Larva::Listener.listen(:my_topic, MyProcessor, "")
|
74
|
+
Propono.publish(:my_topic, {entity: "comment", action: "created", id: 8}
|
75
|
+
```
|
76
|
+
|
77
|
+
With this code `MyProcessor#process` will get called for each message, with extra logging around the call. Within the class you have access to `message`, `action`, `entity` and `id` methods.
|
78
|
+
|
79
|
+
### Worker Pool
|
30
80
|
|
31
|
-
|
81
|
+
The worker pool creates a listener for each topic, and proxies messages to the associated processors. If any processors die, the application will die.
|
82
|
+
|
83
|
+
Creating a worker pool is trivial:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
processors = {
|
87
|
+
my_topic_1: MyProcessor1
|
88
|
+
my_topic_2: MyProcessor2
|
89
|
+
}
|
90
|
+
Larva::WorkerPool.start(processors, "queue-suffix")
|
32
91
|
```
|
33
92
|
|
34
93
|
### Is it any good?
|
data/lib/larva.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Larva
|
2
|
+
class Processor
|
3
|
+
def self.process(message)
|
4
|
+
new(message).process_with_logging
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_accessor :message, :action, :entity, :id
|
8
|
+
def initialize(message)
|
9
|
+
@message = message
|
10
|
+
@action = message[:action]
|
11
|
+
@entity = message[:entity]
|
12
|
+
@id = message[:id]
|
13
|
+
end
|
14
|
+
|
15
|
+
def process_with_logging
|
16
|
+
Propono.config.logger.info "Processing message: #{message}"
|
17
|
+
if self.process
|
18
|
+
Propono.config.logger.info "Message Processed: #{message}"
|
19
|
+
else
|
20
|
+
Propono.config.logger.info "Unrecognized event type, entity: #{entity} action: #{action}."
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/larva/version.rb
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
module Larva
|
2
|
+
class WorkerPool
|
3
|
+
def self.start(processors, queue_suffix)
|
4
|
+
new(processors, queue_suffix).start
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :processors, :queue_suffix, :workers
|
8
|
+
def initialize(processors, queue_suffix)
|
9
|
+
@processors = processors
|
10
|
+
@queue_suffix = queue_suffix
|
11
|
+
end
|
12
|
+
|
13
|
+
def start
|
14
|
+
start_workers
|
15
|
+
keep_workers_alive if workers.count > 0
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def start_workers
|
20
|
+
logger.info "Starting threads."
|
21
|
+
@workers = processors.map do |topic, processor|
|
22
|
+
Thread.new { start_worker(topic, processor) }
|
23
|
+
end
|
24
|
+
logger.info "Threads Started."
|
25
|
+
end
|
26
|
+
|
27
|
+
def start_worker(topic, processor)
|
28
|
+
Larva::Listener.listen(topic, processor, queue_suffix)
|
29
|
+
rescue => e
|
30
|
+
logger.error "Unexpected listener termination: #{e} #{e.backtrace}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def keep_workers_alive
|
34
|
+
sleep(1) while workers.all? { |t| t.alive? }
|
35
|
+
logger.error "Some threads have died"
|
36
|
+
end
|
37
|
+
|
38
|
+
def logger
|
39
|
+
Propono.config.logger
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
module Larva
|
4
|
+
class ProcessorTest < Minitest::Test
|
5
|
+
def test_initialize_should_extract_action_and_entity
|
6
|
+
entity = "media_file"
|
7
|
+
action = "processed"
|
8
|
+
message = {entity: entity, action: action, media_file_id: "8"}
|
9
|
+
processor = Processor.new(message)
|
10
|
+
assert_equal entity, processor.entity
|
11
|
+
assert_equal action, processor.action
|
12
|
+
end
|
13
|
+
|
14
|
+
class GoodProcessor < Processor
|
15
|
+
def process
|
16
|
+
true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class BadProcessor < Processor
|
21
|
+
def process
|
22
|
+
false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_process_logs_message
|
27
|
+
message = {entity: "media_file", action: "processed", media_file_id: "8"}
|
28
|
+
output = "Processing message: #{message}"
|
29
|
+
Propono.config.logger.stubs(:info)
|
30
|
+
Propono.config.logger.expects(:info).with(output)
|
31
|
+
GoodProcessor.process(message)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_process_logs_success
|
35
|
+
message = {entity: "media_file", action: "processed", media_file_id: "8"}
|
36
|
+
output = "Message Processed: #{message}"
|
37
|
+
Propono.config.logger.stubs(:info)
|
38
|
+
Propono.config.logger.expects(:info).with(output)
|
39
|
+
GoodProcessor.process(message)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_process_logs_message
|
43
|
+
entity = "media_file"
|
44
|
+
action = "processed"
|
45
|
+
message = {entity: entity, action: action, media_file_id: "8"}
|
46
|
+
output = "Unrecognized event type, entity: #{entity} action: #{action}."
|
47
|
+
|
48
|
+
Propono.config.logger.stubs(:info)
|
49
|
+
Propono.config.logger.expects(:info).with(output)
|
50
|
+
BadProcessor.process(message)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path('../test_helper', __FILE__)
|
2
|
+
|
3
|
+
module Larva
|
4
|
+
class WorkerPoolTest < Minitest::Test
|
5
|
+
def test_should_complete_for_no_processors
|
6
|
+
WorkerPool.start({}, "")
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_process_logs_start_message
|
10
|
+
Propono.config.logger.stubs(:info)
|
11
|
+
Propono.config.logger.expects(:info).with("Starting threads.")
|
12
|
+
WorkerPool.start({}, "")
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_process_logs_end_message
|
16
|
+
Propono.config.logger.stubs(:info)
|
17
|
+
Propono.config.logger.expects(:info).with("Threads Started.")
|
18
|
+
WorkerPool.start({}, "")
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_start_worker_logs_exception
|
22
|
+
Larva::Listener.expects(:listen).raises(RuntimeError)
|
23
|
+
Propono.config.logger.expects(:error).with do |error|
|
24
|
+
error.start_with?("Unexpected listener termination:")
|
25
|
+
end
|
26
|
+
Propono.config.logger.expects(:error).with('Some threads have died')
|
27
|
+
WorkerPool.start({nil => nil}, "")
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_listen_is_called_correctly
|
31
|
+
topic_name = "Foo"
|
32
|
+
processor = mock
|
33
|
+
queue_suffix = "Bar"
|
34
|
+
Larva::Listener.expects(:listen).with(topic_name, processor, queue_suffix)
|
35
|
+
WorkerPool.start({topic_name => processor}, queue_suffix)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: larva
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- iHiD
|
@@ -102,6 +102,7 @@ extensions: []
|
|
102
102
|
extra_rdoc_files: []
|
103
103
|
files:
|
104
104
|
- .gitignore
|
105
|
+
- .travis.yml
|
105
106
|
- CHANGELOG
|
106
107
|
- CONTRIBUTING.md
|
107
108
|
- Gemfile
|
@@ -111,10 +112,14 @@ files:
|
|
111
112
|
- larva.gemspec
|
112
113
|
- lib/larva.rb
|
113
114
|
- lib/larva/listener.rb
|
115
|
+
- lib/larva/processor.rb
|
114
116
|
- lib/larva/version.rb
|
117
|
+
- lib/larva/worker_pool.rb
|
115
118
|
- test/larva_test.rb
|
116
119
|
- test/listener_test.rb
|
120
|
+
- test/processor_test.rb
|
117
121
|
- test/test_helper.rb
|
122
|
+
- test/worker_pool_test.rb
|
118
123
|
homepage: https://github.com/meducation/larva
|
119
124
|
licenses:
|
120
125
|
- AGPL3
|
@@ -142,5 +147,7 @@ summary: Some Meducation specific helper files for ur pub/sub network
|
|
142
147
|
test_files:
|
143
148
|
- test/larva_test.rb
|
144
149
|
- test/listener_test.rb
|
150
|
+
- test/processor_test.rb
|
145
151
|
- test/test_helper.rb
|
152
|
+
- test/worker_pool_test.rb
|
146
153
|
has_rdoc:
|