fare 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.rspec +4 -0
- data/.travis.yml +10 -0
- data/Gemfile +4 -0
- data/README.md +470 -0
- data/Rakefile +28 -0
- data/bin/fare +48 -0
- data/fare.gemspec +35 -0
- data/features/multiqueue.feature +60 -0
- data/features/multistack.feature +65 -0
- data/features/step_definitions/aruba.rb +1 -0
- data/features/step_definitions/fare_steps.rb +40 -0
- data/features/subscriber.feature +95 -0
- data/features/support/env.rb +34 -0
- data/lib/fare.rb +96 -0
- data/lib/fare/configuration.rb +57 -0
- data/lib/fare/configuration_dsl.rb +134 -0
- data/lib/fare/configuration_when_locked.rb +82 -0
- data/lib/fare/event.rb +26 -0
- data/lib/fare/generate_lock_file.rb +131 -0
- data/lib/fare/load_configuration_file.rb +45 -0
- data/lib/fare/middleware/logging.rb +46 -0
- data/lib/fare/middleware/newrelic.rb +35 -0
- data/lib/fare/middleware/raven.rb +47 -0
- data/lib/fare/publisher.rb +65 -0
- data/lib/fare/queue_adapter.rb +30 -0
- data/lib/fare/rspec.rb +85 -0
- data/lib/fare/subscriber.rb +35 -0
- data/lib/fare/subscriber_cli.rb +270 -0
- data/lib/fare/subscriber_stack.rb +39 -0
- data/lib/fare/test_mode.rb +204 -0
- data/lib/fare/topic.rb +25 -0
- data/lib/fare/topic_adapter.rb +13 -0
- data/lib/fare/update_cli.rb +41 -0
- data/lib/fare/version.rb +3 -0
- data/spec/logger_spec.rb +45 -0
- data/spec/raven_spec.rb +52 -0
- data/spec/rspec_integration_spec.rb +45 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/stubbed_subscribing_spec.rb +66 -0
- metadata +264 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
module Fare
|
4
|
+
module Middleware
|
5
|
+
|
6
|
+
# Use this to log all events and stacktraces:
|
7
|
+
#
|
8
|
+
# Usage:
|
9
|
+
#
|
10
|
+
# use Fare::Middleware::Logging, logger: Logger.new($stdout)
|
11
|
+
class Logging
|
12
|
+
|
13
|
+
def initialize(app, options = {})
|
14
|
+
@app = app
|
15
|
+
@logger = options.fetch(:logger)
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
attrs = env.fetch(:event).attributes
|
20
|
+
start = Time.now
|
21
|
+
begin
|
22
|
+
@app.call(env)
|
23
|
+
rescue Exception => exception
|
24
|
+
duration = Time.now - start
|
25
|
+
@logger.warn("Handled event: %s" % {
|
26
|
+
event: attrs,
|
27
|
+
result: "failure",
|
28
|
+
duration: duration,
|
29
|
+
error_class: exception.class.name,
|
30
|
+
error_message: exception.message,
|
31
|
+
backtrace: exception.backtrace.to_a,
|
32
|
+
}.to_json)
|
33
|
+
raise
|
34
|
+
else
|
35
|
+
duration = Time.now - start
|
36
|
+
@logger.info("Handled event: %s" % {
|
37
|
+
event: attrs,
|
38
|
+
result: "success",
|
39
|
+
duration: duration,
|
40
|
+
}.to_json)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'newrelic_rpm'
|
2
|
+
::NewRelic::Agent.manual_start
|
3
|
+
|
4
|
+
module Fare
|
5
|
+
module Middleware
|
6
|
+
|
7
|
+
# Add NewRelic monitoring to the subscriber.
|
8
|
+
# Make sure you have a newrelic.yml in your config dir.
|
9
|
+
#
|
10
|
+
# Usage:
|
11
|
+
#
|
12
|
+
# subscriber do
|
13
|
+
# setup do
|
14
|
+
# require "fare/middleware/newrelic"
|
15
|
+
# end
|
16
|
+
# always_run do
|
17
|
+
# use Fare::Middleware::NewRelic
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
class NewRelic
|
21
|
+
include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
22
|
+
|
23
|
+
def initialize(app, options = {})
|
24
|
+
@app = app
|
25
|
+
at_exit { ::NewRelic::Agent.shutdown }
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(env)
|
29
|
+
@app.call(env)
|
30
|
+
end
|
31
|
+
add_transaction_tracer :call, :category => :task
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Fare
|
2
|
+
module Middleware
|
3
|
+
|
4
|
+
# Use this to send errors to Sentry:
|
5
|
+
#
|
6
|
+
# Usage:
|
7
|
+
#
|
8
|
+
# use Fare::Middleware::Raven, dsn: "http://...", logger: logger, environment: "production"
|
9
|
+
class Raven
|
10
|
+
|
11
|
+
def initialize(app, options = {})
|
12
|
+
@app = app
|
13
|
+
require "raven" unless defined?(::Raven)
|
14
|
+
configure_sentry(options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
::Raven.extra_context(serialize(env))
|
19
|
+
@app.call(env)
|
20
|
+
rescue Exception => exception
|
21
|
+
::Raven.capture_exception(exception)
|
22
|
+
raise
|
23
|
+
ensure
|
24
|
+
::Raven::Context.clear!
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def configure_sentry(options)
|
30
|
+
::Raven.configure do |config|
|
31
|
+
config.dsn = options.fetch(:dsn)
|
32
|
+
config.logger = options.fetch(:logger)
|
33
|
+
config.environments = [options.fetch(:environment)]
|
34
|
+
config.excluded_exceptions = []
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# removes objects and makes normal hashes, so sentry can read the better
|
39
|
+
def serialize(env)
|
40
|
+
JSON.parse(env.to_json)
|
41
|
+
rescue
|
42
|
+
env
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Fare
|
2
|
+
UnknownTopicError = Class.new(RuntimeError)
|
3
|
+
|
4
|
+
class Publisher
|
5
|
+
|
6
|
+
attr_reader :configuration, :options
|
7
|
+
|
8
|
+
def initialize(configuration, options)
|
9
|
+
@configuration = configuration
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
ensure_topic_publishable!
|
15
|
+
topic.publish(event.serialize)
|
16
|
+
end
|
17
|
+
|
18
|
+
def topic
|
19
|
+
Fare.topic_adapter.fetch(topic_info.fetch("arn"))
|
20
|
+
end
|
21
|
+
|
22
|
+
def topic_info
|
23
|
+
@topic_info ||= configuration.find_publishable_topic(options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def event
|
27
|
+
Event.new(
|
28
|
+
id: "event-#{SecureRandom.uuid}",
|
29
|
+
subject: subject,
|
30
|
+
action: action,
|
31
|
+
payload: payload,
|
32
|
+
source: app_name,
|
33
|
+
version: version,
|
34
|
+
sent_at: Time.now.utc,
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def subject
|
39
|
+
options.fetch(:subject)
|
40
|
+
end
|
41
|
+
|
42
|
+
def action
|
43
|
+
options.fetch(:action)
|
44
|
+
end
|
45
|
+
|
46
|
+
def payload
|
47
|
+
options.fetch(:payload)
|
48
|
+
end
|
49
|
+
|
50
|
+
def version
|
51
|
+
topic_info.fetch("version")
|
52
|
+
end
|
53
|
+
|
54
|
+
def app_name
|
55
|
+
configuration.app_name
|
56
|
+
end
|
57
|
+
|
58
|
+
def ensure_topic_publishable!
|
59
|
+
unless topic_info
|
60
|
+
raise UnknownTopicError, "Topic with subject #{subject} and action #{action} not in lock file, maybe run `fare update`"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Fare
|
2
|
+
class QueueAdapter
|
3
|
+
|
4
|
+
def self.fetch(*args)
|
5
|
+
new(*args).queue
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :environment, :name
|
9
|
+
|
10
|
+
def initialize(environment, name)
|
11
|
+
@environment = environment
|
12
|
+
@name = name
|
13
|
+
end
|
14
|
+
|
15
|
+
def queue
|
16
|
+
sqs.queues.named(queue_name)
|
17
|
+
rescue AWS::SQS::Errors::NonExistentQueue
|
18
|
+
sqs.queues.create(queue_name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def queue_name
|
22
|
+
"#{environment}-#{name}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def sqs
|
26
|
+
AWS::SQS.new
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/fare/rspec.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
begin
|
2
|
+
require "json_expressions"
|
3
|
+
rescue LoadError
|
4
|
+
raise "Please install the gem `json_expressions` to use fare/rspec"
|
5
|
+
end
|
6
|
+
|
7
|
+
module Fare
|
8
|
+
module FareMatcher
|
9
|
+
|
10
|
+
def publish(subject, action, payload = nil)
|
11
|
+
Expectation.new(subject, action, payload)
|
12
|
+
end
|
13
|
+
|
14
|
+
class Expectation
|
15
|
+
|
16
|
+
attr_reader :subject, :action, :payload
|
17
|
+
|
18
|
+
def initialize(subject, action, payload)
|
19
|
+
@subject = subject
|
20
|
+
@action = action
|
21
|
+
@payload = payload
|
22
|
+
end
|
23
|
+
|
24
|
+
def supports_block_expectations?
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
def matches?(expect_block)
|
29
|
+
Fare.stubbed_messages.clear
|
30
|
+
expect_block.call
|
31
|
+
!event.nil? && payload_matches?
|
32
|
+
end
|
33
|
+
|
34
|
+
def does_not_match?(expect_block)
|
35
|
+
raise ArgumentError, "Checking payload with negative expectation is not possible" if payload
|
36
|
+
Fare.stubbed_messages.clear
|
37
|
+
expect_block.call
|
38
|
+
event.nil?
|
39
|
+
end
|
40
|
+
|
41
|
+
def failure_message
|
42
|
+
if event.nil?
|
43
|
+
if Fare.stubbed_messages.size == 0
|
44
|
+
"There were no events published"
|
45
|
+
else
|
46
|
+
"Expected event #{event_name}, but got:\n#{Fare.stubbed_messages.list}"
|
47
|
+
end
|
48
|
+
else
|
49
|
+
"Payload did not match: #{payload_matcher.last_error}\nActual payload was:\n#{event.payload}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def failure_message_when_negated
|
54
|
+
"Expected not to publish #{event_name}, but published it with payload: #{event.payload}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def event_name
|
58
|
+
"#{subject}##{action}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def payload_matches?
|
62
|
+
if payload
|
63
|
+
payload_matcher =~ event.payload
|
64
|
+
else
|
65
|
+
true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def event
|
70
|
+
Fare.stubbed_messages.get(subject, action)
|
71
|
+
end
|
72
|
+
|
73
|
+
def payload_matcher
|
74
|
+
@payload_matcher ||= JsonExpressions::Matcher.new(payload)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
RSpec.configure do |config|
|
84
|
+
config.include Fare::FareMatcher
|
85
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "timeout"
|
2
|
+
|
3
|
+
module Fare
|
4
|
+
class Subscriber
|
5
|
+
UnknownSubscriber = Class.new(ArgumentError)
|
6
|
+
|
7
|
+
attr_reader :configuration
|
8
|
+
|
9
|
+
def initialize(configuration, options = {})
|
10
|
+
name = (options[:name] || configuration.app_name).to_s
|
11
|
+
subscriber_config = configuration.fetch_subscriber(name)
|
12
|
+
subscriber_config.load_setup
|
13
|
+
@sqs_queue = configuration.fetch_subscriber_queue(name)
|
14
|
+
@stacks = subscriber_config.stacks
|
15
|
+
end
|
16
|
+
|
17
|
+
def produce(queue)
|
18
|
+
message = @sqs_queue.receive_message(attributes: [:all])
|
19
|
+
if message
|
20
|
+
queue << message
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def consume(message)
|
25
|
+
event = Event.deserialize(message.body)
|
26
|
+
@stacks.each do |stack|
|
27
|
+
if stack.handles?(event)
|
28
|
+
stack.to_app.call(event: event)
|
29
|
+
message.delete
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,270 @@
|
|
1
|
+
require "daemonic"
|
2
|
+
|
3
|
+
module Fare
|
4
|
+
class SubscriberCLI
|
5
|
+
|
6
|
+
attr_reader :argv, :command
|
7
|
+
|
8
|
+
def initialize(argv)
|
9
|
+
@command = argv.shift
|
10
|
+
@argv = argv
|
11
|
+
end
|
12
|
+
|
13
|
+
def call
|
14
|
+
case command
|
15
|
+
when nil, "-h", "--help", "help"
|
16
|
+
show_help
|
17
|
+
exit 0
|
18
|
+
when "start"
|
19
|
+
start
|
20
|
+
when "stop"
|
21
|
+
stop
|
22
|
+
when "status"
|
23
|
+
status
|
24
|
+
when "restart"
|
25
|
+
restart
|
26
|
+
else
|
27
|
+
puts "Unkown command: #{command}"
|
28
|
+
puts
|
29
|
+
show_help
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def start
|
37
|
+
fare_options = {
|
38
|
+
filename: Fare.default_config_file,
|
39
|
+
environment: (Fare.default_environment || "development"),
|
40
|
+
}
|
41
|
+
daemon_options = {
|
42
|
+
concurrency: 4,
|
43
|
+
startup_timeout: 20,
|
44
|
+
}
|
45
|
+
subscriber_options = {}
|
46
|
+
optparser = OptionParser.new do |parser|
|
47
|
+
|
48
|
+
parser.banner = "Usage: fare subscriber start [options]"
|
49
|
+
|
50
|
+
|
51
|
+
parser.on "-E", "--environment ENV", "Set the environment (default: #{fare_options[:environment]})" do |environment|
|
52
|
+
fare_options[:environment] = environment
|
53
|
+
end
|
54
|
+
|
55
|
+
parser.on "--filename FILENAME", "Location of the Fare configuration file (default: #{fare_options[:filename]})" do |filename|
|
56
|
+
fare_options[:filename] = filename
|
57
|
+
end
|
58
|
+
|
59
|
+
parser.on "--name NAME", "Which named subscriber to run (default is the unnamed one)" do |name|
|
60
|
+
subscriber_options[:name] = name
|
61
|
+
end
|
62
|
+
|
63
|
+
parser.separator ""
|
64
|
+
parser.separator "Process options:"
|
65
|
+
|
66
|
+
parser.on "-c", "--concurrency NUM", Integer, "Set the number of threads (default: #{daemon_options[:concurrency]}" do |concurrency|
|
67
|
+
daemon_options[:concurrency] = concurrency
|
68
|
+
end
|
69
|
+
|
70
|
+
parser.on "-P", "--pid FILE", "The location of the PID file (required when daemonizing)" do |pid|
|
71
|
+
daemon_options[:pid] = pid
|
72
|
+
end
|
73
|
+
|
74
|
+
parser.on "--[no-]daemonize", "Should the subscriber detach?" do |daemonize|
|
75
|
+
daemon_options[:daemonize] = daemonize
|
76
|
+
end
|
77
|
+
|
78
|
+
parser.on "--startup-timeout TIMEOUT", Integer, "How long to wait for the process to start (default: #{daemon_options[:startup_timeout]})" do |timeout|
|
79
|
+
daemon_options[:startup_timeout] = timeout
|
80
|
+
end
|
81
|
+
|
82
|
+
parser.separator ""
|
83
|
+
parser.separator "Logging options:"
|
84
|
+
|
85
|
+
parser.on "--log FILE", "Where to log to" do |log|
|
86
|
+
daemon_options[:log] = log
|
87
|
+
end
|
88
|
+
|
89
|
+
parser.on "--log-level LEVEL", %w(debug info warn fatal), "Set the log level (default: info)" do |level|
|
90
|
+
daemon_options[:log_level] = Logger.const_get(level.upcase)
|
91
|
+
end
|
92
|
+
|
93
|
+
parser.separator ""
|
94
|
+
parser.separator "Other options:"
|
95
|
+
|
96
|
+
parser.on_tail "-h", "--help", "Shows this help page" do
|
97
|
+
puts parser
|
98
|
+
exit
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
optparser.parse!(argv)
|
104
|
+
|
105
|
+
|
106
|
+
Daemonic.start(daemon_options) {
|
107
|
+
Fare.config(fare_options)
|
108
|
+
Subscriber.new(Fare.configuration, subscriber_options)
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
def stop
|
113
|
+
daemon_options = {
|
114
|
+
stop_timeout: 10
|
115
|
+
}
|
116
|
+
optparser = OptionParser.new do |parser|
|
117
|
+
|
118
|
+
parser.banner = "Usage: fare subscriber stop [options]"
|
119
|
+
|
120
|
+
|
121
|
+
parser.separator ""
|
122
|
+
parser.separator "Process options:"
|
123
|
+
|
124
|
+
parser.on "-P", "--pid FILE", "The location of the PID file" do |pid|
|
125
|
+
daemon_options[:pid] = pid
|
126
|
+
end
|
127
|
+
|
128
|
+
parser.on "--stop-timeout TIMEOUT", Integer, "How long to wait for the process to stop (default: #{daemon_options[:stop_timeout]})" do |timeout|
|
129
|
+
daemon_options[:stop_timeout] = timeout
|
130
|
+
end
|
131
|
+
|
132
|
+
parser.separator ""
|
133
|
+
parser.separator "Other options:"
|
134
|
+
|
135
|
+
parser.on_tail "-h", "--help", "Shows this help page" do
|
136
|
+
puts parser
|
137
|
+
exit
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
optparser.parse!(argv)
|
143
|
+
|
144
|
+
Daemonic.stop(daemon_options)
|
145
|
+
end
|
146
|
+
|
147
|
+
def restart
|
148
|
+
fare_options = {
|
149
|
+
filename: Fare.default_config_file,
|
150
|
+
environment: (Fare.default_environment || "development"),
|
151
|
+
}
|
152
|
+
daemon_options = {
|
153
|
+
concurrency: 4,
|
154
|
+
stop_timeout: 10,
|
155
|
+
startup_timeout: 20,
|
156
|
+
}
|
157
|
+
subscriber_options = {}
|
158
|
+
optparser = OptionParser.new do |parser|
|
159
|
+
|
160
|
+
parser.banner = "Usage: fare subscriber start [options]"
|
161
|
+
|
162
|
+
parser.on "-E", "--environment ENV", "Set the environment (default: #{fare_options[:environment]})" do |environment|
|
163
|
+
fare_options[:environment] = environment
|
164
|
+
end
|
165
|
+
|
166
|
+
parser.on "--filename FILENAME", "Location of the Fare configuration file (default: #{fare_options[:filename]})" do |filename|
|
167
|
+
fare_options[:filename] = filename
|
168
|
+
end
|
169
|
+
|
170
|
+
parser.on "--name NAME", "Which named subscriber to run (default is the unnamed one)" do |name|
|
171
|
+
subscriber_options[:name] = name
|
172
|
+
end
|
173
|
+
|
174
|
+
parser.separator ""
|
175
|
+
parser.separator "Process options:"
|
176
|
+
|
177
|
+
parser.on "-c", "--concurrency NUM", Integer, "Set the number of threads (default: #{daemon_options[:concurrency]}" do |concurrency|
|
178
|
+
daemon_options[:concurrency] = concurrency
|
179
|
+
end
|
180
|
+
|
181
|
+
parser.on "-P", "--pid FILE", "The location of the PID file (required)" do |pid|
|
182
|
+
daemon_options[:pid] = pid
|
183
|
+
end
|
184
|
+
|
185
|
+
parser.on "--startup-timeout TIMEOUT", Integer, "How long to wait for the process to start (default: #{daemon_options[:startup_timeout]})" do |timeout|
|
186
|
+
daemon_options[:startup_timeout] = timeout
|
187
|
+
end
|
188
|
+
|
189
|
+
parser.on "--stop-timeout TIMEOUT", Integer, "How long to wait for the process to stop (default: #{daemon_options[:stop_timeout]})" do |timeout|
|
190
|
+
daemon_options[:stop_timeout] = timeout
|
191
|
+
end
|
192
|
+
|
193
|
+
parser.separator ""
|
194
|
+
parser.separator "Logging options:"
|
195
|
+
|
196
|
+
parser.on "--log FILE", "Where to log to" do |log|
|
197
|
+
daemon_options[:log] = log
|
198
|
+
end
|
199
|
+
|
200
|
+
parser.on "--log-level LEVEL", %w(debug info warn fatal), "Set the log level (default: info)" do |level|
|
201
|
+
daemon_options[:log_level] = Logger.const_get(level.upcase)
|
202
|
+
end
|
203
|
+
|
204
|
+
parser.separator ""
|
205
|
+
parser.separator "Other options:"
|
206
|
+
|
207
|
+
parser.on_tail "-h", "--help", "Shows this help page" do
|
208
|
+
puts parser
|
209
|
+
exit
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
optparser.parse!(argv)
|
215
|
+
|
216
|
+
Daemonic.restart(daemon_options) {
|
217
|
+
Fare.config(fare_options)
|
218
|
+
Subscriber.new(Fare.configuration, subscriber_options)
|
219
|
+
}
|
220
|
+
end
|
221
|
+
|
222
|
+
def status
|
223
|
+
daemon_options = {
|
224
|
+
}
|
225
|
+
optparser = OptionParser.new do |parser|
|
226
|
+
|
227
|
+
parser.banner = "Usage: fare subscriber status [options]"
|
228
|
+
|
229
|
+
parser.separator ""
|
230
|
+
parser.separator "Process options:"
|
231
|
+
|
232
|
+
parser.on "-P", "--pid FILE", "The location of the PID file" do |pid|
|
233
|
+
daemon_options[:pid] = pid
|
234
|
+
end
|
235
|
+
|
236
|
+
parser.separator ""
|
237
|
+
parser.separator "Other options:"
|
238
|
+
|
239
|
+
parser.on_tail "-h", "--help", "Shows this help page" do
|
240
|
+
puts parser
|
241
|
+
exit
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|
245
|
+
|
246
|
+
optparser.parse!(argv)
|
247
|
+
|
248
|
+
Daemonic.status(daemon_options)
|
249
|
+
end
|
250
|
+
|
251
|
+
def show_help
|
252
|
+
puts <<-HELP.gsub(/^ +/, '')
|
253
|
+
Usage: fare subscriber COMMAND [OPTIONS]
|
254
|
+
|
255
|
+
Available commands:
|
256
|
+
|
257
|
+
fare subscriber start [options]
|
258
|
+
fare subscriber stop [options]
|
259
|
+
fare subscriber status [options]
|
260
|
+
fare subscriber restart [options]
|
261
|
+
|
262
|
+
You can run any command with the --help option.
|
263
|
+
|
264
|
+
Example: fare subscriber start --help
|
265
|
+
HELP
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
end
|
270
|
+
end
|