opener-daemons 0.1.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 +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +127 -0
- data/Rakefile +1 -0
- data/lib/opener/daemons/controller.rb +162 -0
- data/lib/opener/daemons/daemon.rb +135 -0
- data/lib/opener/daemons/opt_parser.rb +79 -0
- data/lib/opener/daemons/sqs.rb +33 -0
- data/lib/opener/daemons/version.rb +5 -0
- data/lib/opener/daemons.rb +10 -0
- data/opener-daemons.gemspec +27 -0
- metadata +112 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6d0b2126a8b6322257975cfa14b323e8adc2b764
|
4
|
+
data.tar.gz: 9d5cd048fed57092de5bca35d930f25cc7ec1ae5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2e557daafe0982331f859d5c6b0100b1c8cbfedcd8e2256215fc1a4175ceb4628a70c9edef86a962d19bccf769412ee8ea42c2721464fce3d0486689287dea31
|
7
|
+
data.tar.gz: e7d8736c85e18449ba7cf4192bd7840547c05bc12eedcb13651d9db74b302ca6f38e1a519a5a3b432eb114292df25126aeff28d5ccf422edc24f7f385e51bfcf
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Wilco van Duinkerken
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
# Opener::Daemons
|
2
|
+
|
3
|
+
This GEM is part of the OpeNER project, which is the NLP toolchain for the rest
|
4
|
+
of us. This particular GEM makes is possible that al OpeNER components can
|
5
|
+
actually be launched as deamons reading from and push to Amazon SQS queues.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'opener-daemons'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install opener-daemons
|
20
|
+
|
21
|
+
|
22
|
+
## SQS
|
23
|
+
|
24
|
+
The Opener-daemon GEM uses Amazon SQS service as a message service. In order for
|
25
|
+
this to work properly you need an Amazon AWS account and you need to set the
|
26
|
+
following 3 environment variables in your shell:
|
27
|
+
|
28
|
+
```
|
29
|
+
export AWS_ACCESS_KEY_ID='...'
|
30
|
+
export AWS_SECRET_ACCESS_KEY='...'
|
31
|
+
export AWS_REGION='...' #e.g. eu-west-1
|
32
|
+
```
|
33
|
+
|
34
|
+
To see how you specify which queues to use, checkout the usage section below.
|
35
|
+
|
36
|
+
## Implementation
|
37
|
+
|
38
|
+
This Gem is intended for use with other OpeNER components. In order to turn a
|
39
|
+
component in to a Daemon you have to do the following:
|
40
|
+
|
41
|
+
Add the opener-daemons gem to the gemspec of your component (or the the Gemfile
|
42
|
+
if your component is not a gem).
|
43
|
+
|
44
|
+
```
|
45
|
+
gem.add_dependency 'opener-daemons'
|
46
|
+
```
|
47
|
+
|
48
|
+
Create a file in the bin/ directory of the component. Following the OpeNER
|
49
|
+
naming conventions that will be something like this (e.g. the
|
50
|
+
language-identifier). This file provides you with the option to launch a daemon
|
51
|
+
from the command line.
|
52
|
+
|
53
|
+
touch bin/language-identifier-daemon
|
54
|
+
|
55
|
+
Then add the following lines and replace the language-identifier with your own
|
56
|
+
component:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
#!/usr/bin/env ruby
|
60
|
+
require 'rubygems'
|
61
|
+
require 'opener/daemons'
|
62
|
+
|
63
|
+
exec_path = File.expand_path("exec/language-identifier.rb")
|
64
|
+
Opener::Daemons::Controller.new(:name=>"language-identifier",
|
65
|
+
:exec_path=>exec_path)
|
66
|
+
```
|
67
|
+
|
68
|
+
After that you have to create a file that does the actual work in an "exec"
|
69
|
+
directory. From the root of your component do this:
|
70
|
+
|
71
|
+
```
|
72
|
+
mkdir exec
|
73
|
+
touch exec/language-identifier.rb
|
74
|
+
```
|
75
|
+
|
76
|
+
Then copy paste the following code into that file, replacing the
|
77
|
+
"language-identifier" parts with your own component.
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
require 'opener/daemons'
|
81
|
+
require 'opener/language_identifier'
|
82
|
+
|
83
|
+
options = Opener::OptParser.parse!(ARGV)
|
84
|
+
daemon = Opener::Daemon.new(Opener::LanguageIdentifier, options)
|
85
|
+
daemon.start
|
86
|
+
```
|
87
|
+
|
88
|
+
Now you should be able to launch yourself a LanguageIdentifier daemon. Check out
|
89
|
+
the exact usage of the daemon by typing:
|
90
|
+
|
91
|
+
```
|
92
|
+
bin/language-identifier-daemon -h
|
93
|
+
```
|
94
|
+
|
95
|
+
## Usage
|
96
|
+
|
97
|
+
Once you implemented the daemon you can use the -h option to get usage
|
98
|
+
information. It will look like this, with the "language-identifier" strings
|
99
|
+
replaced by your own component.
|
100
|
+
|
101
|
+
```
|
102
|
+
Usage: language-identifier.rb <start|stop|restart> [options]
|
103
|
+
|
104
|
+
Specific options:
|
105
|
+
-i, --input INPUT_QUEUE_NAME Input queue name
|
106
|
+
-o, --output OUTPUT_QUEUE_NAME Output queue name
|
107
|
+
-b, --batch-size BATCH_SIZE Request x messages at once where x is between 1 and 10
|
108
|
+
-w, --workers NUMBER number of worker thread
|
109
|
+
-r, --readers NUMBER number of reader threads
|
110
|
+
-p, --writers NUMBER number of writer / pusher threads
|
111
|
+
--log FILENAME Filename and path of logfile. Defaults to STDOUT
|
112
|
+
--pid FILENAME Filename and path of pidfile. Defaults to /var/run/{filename}.rb
|
113
|
+
--pidpath DIRNAME Directory where to put the PID file. Is Overwritten by --pid if that option is present
|
114
|
+
--debug Turn on debug log level
|
115
|
+
|
116
|
+
Common options:
|
117
|
+
-h, --help Show this message
|
118
|
+
```
|
119
|
+
|
120
|
+
|
121
|
+
## Contributing
|
122
|
+
|
123
|
+
1. Fork it ( http://github.com/<my-github-username>/opener-daemons/fork )
|
124
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
125
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
126
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
127
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,162 @@
|
|
1
|
+
#
|
2
|
+
# Original Idea by Charles Nutter
|
3
|
+
# Copied from: https://gist.github.com/ik5/448884
|
4
|
+
# Then adjusted.
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'opener/daemons'
|
9
|
+
require 'spoon'
|
10
|
+
|
11
|
+
module Opener
|
12
|
+
module Daemons
|
13
|
+
class Controller
|
14
|
+
attr_reader :name, :exec
|
15
|
+
|
16
|
+
def initialize(options={})
|
17
|
+
@exec = options.fetch(:exec_path)
|
18
|
+
@name = determine_name(options[:name])
|
19
|
+
read_commandline
|
20
|
+
end
|
21
|
+
|
22
|
+
def determine_name(name)
|
23
|
+
return identify(name) unless name.nil?
|
24
|
+
get_name_from_exec_path
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_name_from_exec_path
|
28
|
+
File.basename(exec, ".rb")
|
29
|
+
end
|
30
|
+
|
31
|
+
def read_commandline
|
32
|
+
args = ARGV.dup
|
33
|
+
@options = Opener::Daemons::OptParser.parse!(args)
|
34
|
+
|
35
|
+
if ARGV[0] == 'start'
|
36
|
+
start
|
37
|
+
elsif ARGV[0] == 'stop'
|
38
|
+
stop
|
39
|
+
elsif ARGV[0] == 'restart'
|
40
|
+
stop
|
41
|
+
start
|
42
|
+
elsif ARGV[0] == '-h'
|
43
|
+
Opener::Daemons::OptParser.parse!(ARGV)
|
44
|
+
else
|
45
|
+
puts "Usage: #{name} <start|stop|restart> [options]"
|
46
|
+
puts "Or for help use: #{name} -h"
|
47
|
+
exit!
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def pid_path
|
52
|
+
return @pid_path unless @pid_path.nil?
|
53
|
+
@pid_path = if @options[:pid]
|
54
|
+
File.expand_path(@options[:pid])
|
55
|
+
elsif @options[:pidpath]
|
56
|
+
File.expand_path(File.join(@options[:pidpath], "#{name}.pid"))
|
57
|
+
else
|
58
|
+
"/var/run/#{File.basename($0, ".rb")}.pid"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_pid(pid)
|
63
|
+
begin
|
64
|
+
open(pid_path, 'w') do |f|
|
65
|
+
f.puts pid
|
66
|
+
end
|
67
|
+
rescue => e
|
68
|
+
STDERR.puts "Error: Unable to open #{pid_path} for writing:\n\t" +
|
69
|
+
"(#{e.class}) #{e.message}"
|
70
|
+
exit!
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_pid
|
75
|
+
pid = false
|
76
|
+
begin
|
77
|
+
open(pid_path, 'r') do |f|
|
78
|
+
pid = f.readline
|
79
|
+
pid = pid.to_s.gsub(/[^0-9]/,'')
|
80
|
+
end
|
81
|
+
rescue => e
|
82
|
+
STDOUT.puts "Info: Unable to open #{pid_path} for reading:\n\t" +
|
83
|
+
"(#{e.class}) #{e.message}"
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
if pid
|
88
|
+
return pid.to_i
|
89
|
+
else
|
90
|
+
return nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def remove_pidfile
|
95
|
+
begin
|
96
|
+
File.unlink(pid_path)
|
97
|
+
rescue => e
|
98
|
+
STDERR.puts "ERROR: Unable to unlink #{path}:\n\t" +
|
99
|
+
"(#{e.class}) #{e.message}"
|
100
|
+
exit
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def process_exists?
|
105
|
+
begin
|
106
|
+
pid = get_pid
|
107
|
+
return false unless pid
|
108
|
+
Process.kill(0, pid)
|
109
|
+
true
|
110
|
+
rescue Errno::ESRCH, TypeError # "PID is NOT running or is zombied
|
111
|
+
false
|
112
|
+
rescue Errno::EPERM
|
113
|
+
STDERR.puts "No permission to query #{pid}!";
|
114
|
+
false
|
115
|
+
rescue => e
|
116
|
+
STDERR.puts "Error: Unable to determine status for pid: #{pid}.\n\t" +
|
117
|
+
"(#{e.class}) #{e.message}"
|
118
|
+
false
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def stop
|
123
|
+
begin
|
124
|
+
pid = get_pid
|
125
|
+
STDOUT.puts "Stopping pid: #{pid}"
|
126
|
+
while true do
|
127
|
+
Process.kill("TERM", pid)
|
128
|
+
Process.wait(pid)
|
129
|
+
sleep(0.1)
|
130
|
+
end
|
131
|
+
rescue Errno::ESRCH # no more process to kill
|
132
|
+
remove_pidfile
|
133
|
+
STDOUT.puts 'Stopped the process'
|
134
|
+
rescue => e
|
135
|
+
STDERR.puts "Unable to terminate process: (#{e.class}) #{e.message}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def start
|
140
|
+
if process_exists?
|
141
|
+
STDERR.puts "Error: The process #{name} already running. Restarting the process"
|
142
|
+
stop
|
143
|
+
end
|
144
|
+
|
145
|
+
STDOUT.puts "Starting DAEMON"
|
146
|
+
pid = Spoon.spawnp exec, *ARGV
|
147
|
+
STDOUT.puts "Started DAEMON"
|
148
|
+
create_pid(pid)
|
149
|
+
begin
|
150
|
+
Process.setsid
|
151
|
+
rescue Errno::EPERM => e
|
152
|
+
STDERR.puts "Process.setsid not permitted on this platform, not critical. Continuing normal operations.\n\t (#{e.class}) #{e.message}"
|
153
|
+
end
|
154
|
+
File::umask(0)
|
155
|
+
end
|
156
|
+
|
157
|
+
def identify(string)
|
158
|
+
string.gsub(/\W/,"-").gsub("--","-")
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'opener/daemons/sqs'
|
3
|
+
|
4
|
+
module Opener
|
5
|
+
module Daemons
|
6
|
+
class Daemon
|
7
|
+
attr_reader :batch_size,
|
8
|
+
:input_queue, :output_queue,
|
9
|
+
:input_buffer, :output_buffer,
|
10
|
+
:klass,
|
11
|
+
:logger
|
12
|
+
|
13
|
+
attr_accessor :threads, :thread_counts
|
14
|
+
|
15
|
+
def initialize(klass, options={})
|
16
|
+
@input_queue = Opener::Daemons::SQS.find(options.fetch(:input_queue))
|
17
|
+
@output_queue = Opener::Daemons::SQS.find(options.fetch(:output_queue))
|
18
|
+
|
19
|
+
@threads = {}
|
20
|
+
@threads[:writers] = []
|
21
|
+
@threads[:readers] = []
|
22
|
+
@threads[:workers] = []
|
23
|
+
|
24
|
+
@thread_counts = {}
|
25
|
+
@thread_counts[:workers] = options.fetch(:workers, 1)
|
26
|
+
@thread_counts[:readers] = options.fetch(:readers, 5)
|
27
|
+
@thread_counts[:writers] = options.fetch(:writers, 1)
|
28
|
+
|
29
|
+
@batch_size = options.fetch(:batch_size, 10)
|
30
|
+
|
31
|
+
@input_buffer = Queue.new
|
32
|
+
@output_buffer = Queue.new
|
33
|
+
|
34
|
+
@klass = klass
|
35
|
+
|
36
|
+
script_name = File.basename($0, ".rb")
|
37
|
+
@logger = Logger.new(options.fetch(:log, "#{script_name}.log"))
|
38
|
+
@logger.level = if options.fetch(:debug, false)
|
39
|
+
Logger::DEBUG
|
40
|
+
else
|
41
|
+
Logger::INFO
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def buffer_new_messages
|
46
|
+
if input_buffer.size > buffer_size
|
47
|
+
#logger.debug "Maximum input buffer size reached"
|
48
|
+
return
|
49
|
+
end
|
50
|
+
|
51
|
+
if output_buffer.size > buffer_size
|
52
|
+
#logger.debug "Maximum output buffer size reached"
|
53
|
+
return
|
54
|
+
end
|
55
|
+
|
56
|
+
messages = input_queue.receive_messages(batch_size)
|
57
|
+
|
58
|
+
return if messages.nil?
|
59
|
+
messages.each do |message|
|
60
|
+
input_buffer << message
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def start
|
65
|
+
Thread.abort_on_exception = true
|
66
|
+
#
|
67
|
+
# Load Readers
|
68
|
+
#
|
69
|
+
thread_counts[:readers].times do |t|
|
70
|
+
threads[:readers] << Thread.new do
|
71
|
+
logger.info "Producer #{t+1} ready for action..."
|
72
|
+
loop do
|
73
|
+
buffer_new_messages
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Load Workers
|
80
|
+
#
|
81
|
+
thread_counts[:workers].times do |t|
|
82
|
+
threads[:workers] << Thread.new do
|
83
|
+
logger.info "Worker #{t+1} launching..."
|
84
|
+
identifier = klass.new
|
85
|
+
loop do
|
86
|
+
message = input_buffer.pop
|
87
|
+
|
88
|
+
input = JSON.parse(message[:body])["input"]
|
89
|
+
begin
|
90
|
+
output = identifier.run(input)
|
91
|
+
rescue Exception => e
|
92
|
+
logger.error(e)
|
93
|
+
output = input
|
94
|
+
end
|
95
|
+
output_buffer.push({ :output=>output,
|
96
|
+
:handle=>message[:receipt_handle]})
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Load Writers
|
103
|
+
#
|
104
|
+
thread_counts[:writers].times do |t|
|
105
|
+
threads[:writers] << Thread.new do
|
106
|
+
logger.info "Pusher #{t+1} ready for action..."
|
107
|
+
loop do
|
108
|
+
message = output_buffer.pop
|
109
|
+
|
110
|
+
payload = {:input=>message[:output]}.to_json
|
111
|
+
output_queue.send_message(payload)
|
112
|
+
input_queue.delete_message(message[:handle])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
reporter = Thread.new do
|
118
|
+
loop do
|
119
|
+
logger.debug "input buffer: #{input_buffer.size} \t output buffer: #{output_buffer.size}"
|
120
|
+
sleep(2)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
threads[:writers].each(&:join)
|
125
|
+
threads[:readers].each(&:join)
|
126
|
+
threads[:workers].each(&:join)
|
127
|
+
end
|
128
|
+
|
129
|
+
def buffer_size
|
130
|
+
4 * batch_size
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Opener
|
4
|
+
module Daemons
|
5
|
+
class OptParser
|
6
|
+
|
7
|
+
def self.parse(args)
|
8
|
+
process(args, :parse)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.parse!(args)
|
12
|
+
process(args, :parse!)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.process(args, call)
|
16
|
+
options = {}
|
17
|
+
|
18
|
+
OptionParser.new do |opts|
|
19
|
+
opts.banner = "Usage: language-identifier.rb <start|stop|restart> [options]"
|
20
|
+
opts.separator ""
|
21
|
+
opts.separator "Specific options:"
|
22
|
+
|
23
|
+
opts.on("-i", "--input INPUT_QUEUE_NAME", "Input queue name") do |v|
|
24
|
+
options[:input_queue] = v
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-o", "--output OUTPUT_QUEUE_NAME", "Output queue name") do |v|
|
28
|
+
options[:output_queue] = v
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("-b", "--batch-size BATCH_SIZE", Integer, "Request x messages at once where x is between 1 and 10") do |v|
|
32
|
+
options[:batch_size] = v
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("-w", "--workers NUMBER", Integer, "number of worker thread") do |v|
|
36
|
+
options[:workers] = v
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on("-r", "--readers NUMBER", Integer, "number of reader threads") do |v|
|
40
|
+
options[:readers] = v
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on("-p", "--writers NUMBER", Integer, "number of writer / pusher threads") do |v|
|
44
|
+
options[:writers] = v
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on("--log FILENAME", "Filename and path of logfile. Defaults to STDOUT") do |v|
|
48
|
+
options[:log] = v
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.on("--pid FILENAME", "Filename and path of pidfile. Defaults to /var/run/{basename of current script}.pid") do |v|
|
52
|
+
options[:pid] = v
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on("--pidpath DIRNAME", "Directory where to put the PID file. Is Overwritten by --pid if that option is present") do |v|
|
56
|
+
options[:pidpath] = v
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on("--debug", "Turn on debug log level") do |v|
|
60
|
+
options[:debug] = true
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.separator ""
|
64
|
+
|
65
|
+
opts.separator "Common options:"
|
66
|
+
|
67
|
+
# No argument, shows at tail. This will print an options summary.
|
68
|
+
# Try it and see!
|
69
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
70
|
+
puts opts
|
71
|
+
exit
|
72
|
+
end
|
73
|
+
end.send(call, args)
|
74
|
+
|
75
|
+
return options
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'aws-sdk-core'
|
2
|
+
|
3
|
+
module Opener
|
4
|
+
module Daemons
|
5
|
+
class SQS
|
6
|
+
attr_reader :sqs, :name, :url
|
7
|
+
|
8
|
+
def self.find(name)
|
9
|
+
new(name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(name)
|
13
|
+
@sqs = Aws::SQS.new
|
14
|
+
@name = name
|
15
|
+
@url = sqs.get_queue_url(:queue_name=>name)[:queue_url]
|
16
|
+
end
|
17
|
+
|
18
|
+
def send_message(message)
|
19
|
+
sqs.send_message(:queue_url=>url, :message_body=>message)
|
20
|
+
end
|
21
|
+
|
22
|
+
def delete_message(handle)
|
23
|
+
sqs.delete_message(:queue_url=>url, :receipt_handle=>handle)
|
24
|
+
end
|
25
|
+
|
26
|
+
def receive_messages(limit)
|
27
|
+
result = sqs.receive_message(:queue_url=>url,
|
28
|
+
:max_number_of_messages=>limit)[:messages]
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'opener/daemons/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "opener-daemons"
|
8
|
+
spec.version = Opener::Daemons::VERSION
|
9
|
+
spec.authors = ["Wilco van Duinkerken"]
|
10
|
+
spec.email = ["wilco@sparkboxx.com"]
|
11
|
+
spec.summary = %q{Daemonize OpeNER components and make them read from an SQS queue. JRuby compatible.}
|
12
|
+
spec.description = spec.summary
|
13
|
+
spec.homepage = "http://opener-project.github.io"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
|
22
|
+
spec.add_dependency 'aws-sdk-core'
|
23
|
+
spec.add_dependency 'spoon'
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: opener-daemons
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Wilco van Duinkerken
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aws-sdk-core
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
requirement: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - '>='
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: '0'
|
25
|
+
prerelease: false
|
26
|
+
type: :runtime
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: spoon
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
prerelease: false
|
40
|
+
type: :runtime
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.5'
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ~>
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '1.5'
|
53
|
+
prerelease: false
|
54
|
+
type: :development
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirement: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
prerelease: false
|
68
|
+
type: :development
|
69
|
+
description: Daemonize OpeNER components and make them read from an SQS queue. JRuby compatible.
|
70
|
+
email:
|
71
|
+
- wilco@sparkboxx.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lib/opener/daemons.rb
|
82
|
+
- lib/opener/daemons/controller.rb
|
83
|
+
- lib/opener/daemons/daemon.rb
|
84
|
+
- lib/opener/daemons/opt_parser.rb
|
85
|
+
- lib/opener/daemons/sqs.rb
|
86
|
+
- lib/opener/daemons/version.rb
|
87
|
+
- opener-daemons.gemspec
|
88
|
+
homepage: http://opener-project.github.io
|
89
|
+
licenses:
|
90
|
+
- MIT
|
91
|
+
metadata: {}
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options: []
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 2.2.2
|
109
|
+
signing_key:
|
110
|
+
specification_version: 4
|
111
|
+
summary: Daemonize OpeNER components and make them read from an SQS queue. JRuby compatible.
|
112
|
+
test_files: []
|