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 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
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in opener-daemons.gemspec
4
+ gemspec
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,5 @@
1
+ module Opener
2
+ module Daemons
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ require "opener/daemons/version"
2
+ require "opener/daemons/sqs"
3
+ require "opener/daemons/daemon"
4
+ require "opener/daemons/opt_parser"
5
+ require "opener/daemons/controller"
6
+
7
+ module Opener
8
+ module Daemons
9
+ end
10
+ 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: []