karafka 0.5.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 +68 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +202 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +216 -0
- data/MIT-LICENCE +18 -0
- data/README.md +831 -0
- data/Rakefile +17 -0
- data/bin/karafka +7 -0
- data/karafka.gemspec +34 -0
- data/lib/karafka.rb +73 -0
- data/lib/karafka/app.rb +45 -0
- data/lib/karafka/base_controller.rb +162 -0
- data/lib/karafka/base_responder.rb +118 -0
- data/lib/karafka/base_worker.rb +41 -0
- data/lib/karafka/capistrano.rb +2 -0
- data/lib/karafka/capistrano/karafka.cap +84 -0
- data/lib/karafka/cli.rb +52 -0
- data/lib/karafka/cli/base.rb +74 -0
- data/lib/karafka/cli/console.rb +23 -0
- data/lib/karafka/cli/flow.rb +46 -0
- data/lib/karafka/cli/info.rb +26 -0
- data/lib/karafka/cli/install.rb +45 -0
- data/lib/karafka/cli/routes.rb +39 -0
- data/lib/karafka/cli/server.rb +59 -0
- data/lib/karafka/cli/worker.rb +26 -0
- data/lib/karafka/connection/consumer.rb +29 -0
- data/lib/karafka/connection/listener.rb +54 -0
- data/lib/karafka/connection/message.rb +17 -0
- data/lib/karafka/connection/topic_consumer.rb +48 -0
- data/lib/karafka/errors.rb +50 -0
- data/lib/karafka/fetcher.rb +40 -0
- data/lib/karafka/helpers/class_matcher.rb +77 -0
- data/lib/karafka/helpers/multi_delegator.rb +31 -0
- data/lib/karafka/loader.rb +77 -0
- data/lib/karafka/logger.rb +52 -0
- data/lib/karafka/monitor.rb +82 -0
- data/lib/karafka/params/interchanger.rb +33 -0
- data/lib/karafka/params/params.rb +102 -0
- data/lib/karafka/patches/dry/configurable/config.rb +37 -0
- data/lib/karafka/process.rb +61 -0
- data/lib/karafka/responders/builder.rb +33 -0
- data/lib/karafka/responders/topic.rb +43 -0
- data/lib/karafka/responders/usage_validator.rb +59 -0
- data/lib/karafka/routing/builder.rb +89 -0
- data/lib/karafka/routing/route.rb +80 -0
- data/lib/karafka/routing/router.rb +38 -0
- data/lib/karafka/server.rb +53 -0
- data/lib/karafka/setup/config.rb +57 -0
- data/lib/karafka/setup/configurators/base.rb +33 -0
- data/lib/karafka/setup/configurators/celluloid.rb +20 -0
- data/lib/karafka/setup/configurators/sidekiq.rb +34 -0
- data/lib/karafka/setup/configurators/water_drop.rb +19 -0
- data/lib/karafka/setup/configurators/worker_glass.rb +13 -0
- data/lib/karafka/status.rb +23 -0
- data/lib/karafka/templates/app.rb.example +26 -0
- data/lib/karafka/templates/application_controller.rb.example +5 -0
- data/lib/karafka/templates/application_responder.rb.example +9 -0
- data/lib/karafka/templates/application_worker.rb.example +12 -0
- data/lib/karafka/templates/config.ru.example +13 -0
- data/lib/karafka/templates/sidekiq.yml.example +26 -0
- data/lib/karafka/version.rb +6 -0
- data/lib/karafka/workers/builder.rb +49 -0
- data/log/.gitkeep +0 -0
- metadata +267 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
module Karafka
|
2
|
+
# Worker wrapper for Sidekiq workers
|
3
|
+
class BaseWorker
|
4
|
+
include Sidekiq::Worker
|
5
|
+
|
6
|
+
attr_accessor :params, :topic
|
7
|
+
|
8
|
+
# Executes the logic that lies in #perform Karafka controller method
|
9
|
+
# @param topic [String] Topic that we will use to route to a proper controller
|
10
|
+
# @param params [Hash] params hash that we use to build Karafka params object
|
11
|
+
def perform(topic, params)
|
12
|
+
self.topic = topic
|
13
|
+
self.params = params
|
14
|
+
Karafka.monitor.notice(self.class, controller.to_h)
|
15
|
+
controller.perform
|
16
|
+
end
|
17
|
+
|
18
|
+
# What action should be taken when perform method fails
|
19
|
+
# @param topic [String] Topic bthat we will use to route to a proper controller
|
20
|
+
# @param params [Hash] params hash that we use to build Karafka params object
|
21
|
+
def after_failure(topic, params)
|
22
|
+
self.topic = topic
|
23
|
+
self.params = params
|
24
|
+
|
25
|
+
return unless controller.respond_to?(:after_failure)
|
26
|
+
|
27
|
+
Karafka.monitor.notice(self.class, controller.to_h)
|
28
|
+
controller.after_failure
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# @return [Karafka::Controller] descendant of Karafka::BaseController that matches the topic
|
34
|
+
# with params assigned already (controller is ready to use)
|
35
|
+
def controller
|
36
|
+
@controller ||= Karafka::Routing::Router.new(topic).build.tap do |ctrl|
|
37
|
+
ctrl.params = ctrl.interchanger.parse(params)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# @note Inspired by Puma capistrano handlers
|
2
|
+
# @see https://github.com/seuros/capistrano-puma/blob/master/lib/capistrano/tasks/puma.rake
|
3
|
+
namespace :load do
|
4
|
+
task :defaults do
|
5
|
+
set :karafka_default_hooks, -> { true }
|
6
|
+
set :karafka_env, -> { fetch(:karafka_env, fetch(:environment)) }
|
7
|
+
set :karafka_pid, -> { File.join(shared_path, 'tmp', 'pids', 'karafka.pid') }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
namespace :deploy do
|
12
|
+
before :starting, :check_karafka_hooks do
|
13
|
+
invoke 'karafka:add_default_hooks' if fetch(:karafka_default_hooks)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
namespace :karafka do
|
18
|
+
desc 'Stop Karafka'
|
19
|
+
task :stop do
|
20
|
+
on roles(:app) do |host|
|
21
|
+
within shared_path do
|
22
|
+
# If there's no pidfile it means that Karafka is not running
|
23
|
+
next unless test "cat #{fetch(:karafka_pid)}"
|
24
|
+
|
25
|
+
# Send a kill signal to a given process
|
26
|
+
execute "kill -INT `cat #{fetch(:karafka_pid)}`"
|
27
|
+
|
28
|
+
# And wait until it finishes. We wait because we don't want to start next process until
|
29
|
+
# the previous one is stopped. That way we won't have problems with Kafka registering and
|
30
|
+
# deregistering processes from topics (although nothing bad would happen. It would just
|
31
|
+
# take more time to rebalance)
|
32
|
+
while true
|
33
|
+
break unless test "cat #{fetch(:karafka_pid)}"
|
34
|
+
info 'Waiting for Karafka to stop'
|
35
|
+
sleep 5
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Start Karafka'
|
42
|
+
task :start do
|
43
|
+
on roles(:app) do |host|
|
44
|
+
within current_path do
|
45
|
+
# We use all 3 because when combined with Sinatra/Rails it will use their parts as well
|
46
|
+
# so we want to set proper env for any of them
|
47
|
+
with(
|
48
|
+
KARAFKA_ENV: fetch(:karafka_env),
|
49
|
+
RAILS_ENV: fetch(:rails_env),
|
50
|
+
RACK_ENV: fetch(:rack_env)
|
51
|
+
)do
|
52
|
+
execute :bundle, "exec karafka server -d -p #{fetch(:karafka_pid)}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
desc 'Restart Karafka'
|
59
|
+
task :restart do
|
60
|
+
invoke 'karafka:stop'
|
61
|
+
invoke 'karafka:start'
|
62
|
+
end
|
63
|
+
|
64
|
+
desc 'Status Karafka'
|
65
|
+
task :status do
|
66
|
+
on roles(:app) do |host|
|
67
|
+
if test "cat #{fetch(:karafka_pid)}"
|
68
|
+
pid = capture "cat #{fetch(:karafka_pid)}"
|
69
|
+
|
70
|
+
if test "ps -p #{pid} > /dev/null"
|
71
|
+
info "Karafka is started: #{pid}"
|
72
|
+
else
|
73
|
+
error "Karafka is not started but pidfile exists"
|
74
|
+
end
|
75
|
+
else
|
76
|
+
info "Karafka is not started"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
task :add_default_hooks do
|
82
|
+
after 'deploy:finished', 'karafka:restart'
|
83
|
+
end
|
84
|
+
end
|
data/lib/karafka/cli.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Karafka
|
2
|
+
# Karafka framework Cli
|
3
|
+
# If you want to add/modify command that belongs to CLI, please review all commands
|
4
|
+
# available in cli/ directory inside Karafka source code.
|
5
|
+
#
|
6
|
+
# @note Whole Cli is built using Thor
|
7
|
+
# @see https://github.com/erikhuda/thor
|
8
|
+
class Cli
|
9
|
+
package_name 'Karafka'
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# Loads all Cli commands into Thor framework
|
13
|
+
# This method should be executed before we run Karafka::Cli.start, otherwise we won't
|
14
|
+
# have any Cli commands available
|
15
|
+
def prepare
|
16
|
+
cli_commands.each do |action|
|
17
|
+
action.bind_to(self)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# @return [Array<Class>] Array with Cli action classes that can be used as commands
|
24
|
+
def cli_commands
|
25
|
+
constants
|
26
|
+
.map! { |object| const_get(object) }
|
27
|
+
.keep_if do |object|
|
28
|
+
object.instance_of?(Class) && (object < Cli::Base)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# This is kinda trick - since we don't have a autoload and other magic stuff
|
36
|
+
# like Rails does, so instead this method allows us to replace currently running
|
37
|
+
# console with a new one via Kernel.exec. It will start console with new code loaded
|
38
|
+
# Yes we know that it is not turbofast, however it is turbo convinient and small
|
39
|
+
#
|
40
|
+
# Also - the KARAFKA_CONSOLE is used to detect that we're executing the irb session
|
41
|
+
# so this method is only available when the Karafka console is running
|
42
|
+
#
|
43
|
+
# We skip this because this should exist and be only valid in the console
|
44
|
+
# :nocov:
|
45
|
+
if ENV['KARAFKA_CONSOLE']
|
46
|
+
# Reloads Karafka irb console session
|
47
|
+
def reload!
|
48
|
+
puts "Reloading...\n"
|
49
|
+
Kernel.exec Karafka::Cli::Console.command
|
50
|
+
end
|
51
|
+
end
|
52
|
+
# :nocov:
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Karafka
|
2
|
+
class Cli < Thor
|
3
|
+
# Base class for all the command that we want to define
|
4
|
+
# This base class provides a nicer interface to Thor and allows to easier separate single
|
5
|
+
# independent commands
|
6
|
+
# In order to define a new command you need to:
|
7
|
+
# - specify its desc
|
8
|
+
# - implement call method
|
9
|
+
#
|
10
|
+
# @example Create a dummy command
|
11
|
+
# class Dummy < Base
|
12
|
+
# self.desc = 'Dummy command'
|
13
|
+
#
|
14
|
+
# def call
|
15
|
+
# puts 'I'm doing nothing!
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
class Base
|
19
|
+
# We can use it to call other cli methods via this object
|
20
|
+
attr_reader :cli
|
21
|
+
|
22
|
+
# @param cli [Karafka::Cli] current Karafka Cli instance
|
23
|
+
def initialize(cli)
|
24
|
+
@cli = cli
|
25
|
+
end
|
26
|
+
|
27
|
+
# This method should implement proper cli action
|
28
|
+
def call
|
29
|
+
raise NotImplementedError, 'Implement this in a subclass'
|
30
|
+
end
|
31
|
+
|
32
|
+
class << self
|
33
|
+
# Allows to set options for Thor cli
|
34
|
+
# @see https://github.com/erikhuda/thor
|
35
|
+
# @param option Single option details
|
36
|
+
def option(*option)
|
37
|
+
@options ||= []
|
38
|
+
@options << option
|
39
|
+
end
|
40
|
+
|
41
|
+
# Allows to set description of a given cli command
|
42
|
+
# @param desc [String] Description of a given cli command
|
43
|
+
def desc(desc)
|
44
|
+
@desc ||= desc
|
45
|
+
end
|
46
|
+
|
47
|
+
# This method will bind a given Cli command into Karafka Cli
|
48
|
+
# This method is a wrapper to way Thor defines its commands
|
49
|
+
# @param cli_class [Karafka::Cli] Karafka cli_class
|
50
|
+
def bind_to(cli_class)
|
51
|
+
cli_class.desc name, @desc
|
52
|
+
|
53
|
+
(@options || []).each { |option| cli_class.option(*option) }
|
54
|
+
|
55
|
+
context = self
|
56
|
+
|
57
|
+
cli_class.send :define_method, name do |*args|
|
58
|
+
context.new(self).call(*args)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
# @return [String] downcased current class name that we use to define name for
|
65
|
+
# given Cli command
|
66
|
+
# @example for Karafka::Cli::Install
|
67
|
+
# name #=> 'install'
|
68
|
+
def name
|
69
|
+
to_s.split('::').last.downcase
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Karafka
|
2
|
+
# Karafka framework Cli
|
3
|
+
class Cli
|
4
|
+
# Console Karafka Cli action
|
5
|
+
class Console < Base
|
6
|
+
desc 'Start the Karafka console (short-cut alias: "c")'
|
7
|
+
option aliases: 'c'
|
8
|
+
|
9
|
+
# @return [String] Console executing command
|
10
|
+
# @example
|
11
|
+
# Karafka::Cli::Console.command #=> 'KARAFKA_CONSOLE=true bundle exec irb...'
|
12
|
+
def self.command
|
13
|
+
"KARAFKA_CONSOLE=true bundle exec irb -r #{Karafka.boot_file}"
|
14
|
+
end
|
15
|
+
|
16
|
+
# Start the Karafka console
|
17
|
+
def call
|
18
|
+
cli.info
|
19
|
+
system self.class.command
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Karafka
|
2
|
+
# Karafka framework Cli
|
3
|
+
class Cli
|
4
|
+
# Description of topics flow (incoming/outgoing)
|
5
|
+
class Flow < Base
|
6
|
+
desc 'Print application data flow (incoming => outgoing)'
|
7
|
+
|
8
|
+
# Print out all defined routes in alphabetical order
|
9
|
+
def call
|
10
|
+
routes.each do |route|
|
11
|
+
any_topics = !route.responder&.topics.nil?
|
12
|
+
|
13
|
+
if any_topics
|
14
|
+
puts "#{route.topic} =>"
|
15
|
+
|
16
|
+
route.responder.topics.each do |_name, topic|
|
17
|
+
features = []
|
18
|
+
features << (topic.required? ? 'always' : 'conditionally')
|
19
|
+
features << (topic.multiple_usage? ? 'one or more' : 'exactly once')
|
20
|
+
|
21
|
+
print topic.name, "(#{features.join(', ')})"
|
22
|
+
end
|
23
|
+
else
|
24
|
+
puts "#{route.topic} => (nothing)"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# @return [Array<Karafka::Routing::Route>] all routes sorted in alphabetical order
|
32
|
+
def routes
|
33
|
+
Karafka::App.routes.sort do |route1, route2|
|
34
|
+
route1.topic <=> route2.topic
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Prints a given value with label in a nice way
|
39
|
+
# @param label [String] label describing value
|
40
|
+
# @param value [String] value that should be printed
|
41
|
+
def print(label, value)
|
42
|
+
printf "%-25s %s\n", " - #{label}:", value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Karafka
|
2
|
+
# Karafka framework Cli
|
3
|
+
class Cli
|
4
|
+
# Info Karafka Cli action
|
5
|
+
class Info < Base
|
6
|
+
desc 'Print configuration details and other options of your application'
|
7
|
+
|
8
|
+
# Print configuration details and other options of your application
|
9
|
+
def call
|
10
|
+
config = Karafka::App.config
|
11
|
+
|
12
|
+
info = [
|
13
|
+
"Karafka framework version: #{Karafka::VERSION}",
|
14
|
+
"Application name: #{config.name}",
|
15
|
+
"Number of threads: #{config.concurrency}",
|
16
|
+
"Boot file: #{Karafka.boot_file}",
|
17
|
+
"Environment: #{Karafka.env}",
|
18
|
+
"Kafka hosts: #{config.kafka.hosts}",
|
19
|
+
"Redis: #{config.redis.to_h}"
|
20
|
+
]
|
21
|
+
|
22
|
+
puts(info.join("\n"))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Karafka
|
2
|
+
# Karafka framework Cli
|
3
|
+
class Cli
|
4
|
+
# Install Karafka Cli action
|
5
|
+
class Install < Base
|
6
|
+
desc 'Install all required things for Karafka application in current directory'
|
7
|
+
|
8
|
+
# Directories created by default
|
9
|
+
INSTALL_DIRS = %w(
|
10
|
+
app/models
|
11
|
+
app/controllers
|
12
|
+
app/responders
|
13
|
+
app/workers
|
14
|
+
config
|
15
|
+
log
|
16
|
+
tmp/pids
|
17
|
+
).freeze
|
18
|
+
|
19
|
+
# Where should we map proper files from templates
|
20
|
+
INSTALL_FILES_MAP = {
|
21
|
+
'app.rb.example' => Karafka.boot_file.basename,
|
22
|
+
'config.ru.example' => 'config.ru',
|
23
|
+
'sidekiq.yml.example' => 'config/sidekiq.yml.example',
|
24
|
+
'application_worker.rb.example' => 'app/workers/application_worker.rb',
|
25
|
+
'application_controller.rb.example' => 'app/controllers/application_controller.rb',
|
26
|
+
'application_responder.rb.example' => 'app/responders/application_responder.rb'
|
27
|
+
}.freeze
|
28
|
+
|
29
|
+
# Install all required things for Karafka application in current directory
|
30
|
+
def call
|
31
|
+
INSTALL_DIRS.each do |dir|
|
32
|
+
FileUtils.mkdir_p Karafka.root.join(dir)
|
33
|
+
end
|
34
|
+
|
35
|
+
INSTALL_FILES_MAP.each do |source, target|
|
36
|
+
target = Karafka.root.join(target)
|
37
|
+
next if File.exist?(target)
|
38
|
+
|
39
|
+
source = Karafka.core_root.join("templates/#{source}")
|
40
|
+
FileUtils.cp_r(source, target)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Karafka
|
2
|
+
# Karafka framework Cli
|
3
|
+
class Cli
|
4
|
+
# Routes Karafka Cli action
|
5
|
+
class Routes < Base
|
6
|
+
desc 'Print out all defined routes in alphabetical order'
|
7
|
+
option aliases: 'r'
|
8
|
+
|
9
|
+
# Print out all defined routes in alphabetical order
|
10
|
+
def call
|
11
|
+
routes.each do |route|
|
12
|
+
puts "#{route.topic}:"
|
13
|
+
print('Group', route.group)
|
14
|
+
print('Controller', route.controller)
|
15
|
+
print('Worker', route.worker)
|
16
|
+
print('Parser', route.parser)
|
17
|
+
print('Interchanger', route.interchanger)
|
18
|
+
print('Responder', route.responder)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# @return [Array<Karafka::Routing::Route>] all routes sorted in alphabetical order
|
25
|
+
def routes
|
26
|
+
Karafka::App.routes.sort do |route1, route2|
|
27
|
+
route1.topic <=> route2.topic
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Prints a given value with label in a nice way
|
32
|
+
# @param label [String] label describing value
|
33
|
+
# @param value [String] value that should be printed
|
34
|
+
def print(label, value)
|
35
|
+
printf "%-18s %s\n", " - #{label}:", value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Karafka
|
2
|
+
# Karafka framework Cli
|
3
|
+
class Cli
|
4
|
+
# Server Karafka Cli action
|
5
|
+
class Server < Base
|
6
|
+
desc 'Start the Karafka server (short-cut alias: "s")'
|
7
|
+
option aliases: 's'
|
8
|
+
option :daemon, default: false, type: :boolean, aliases: :d
|
9
|
+
option :pid, default: 'tmp/pids/karafka', type: :string, aliases: :p
|
10
|
+
|
11
|
+
# Start the Karafka server
|
12
|
+
def call
|
13
|
+
puts 'Starting Karafka server'
|
14
|
+
cli.info
|
15
|
+
|
16
|
+
if cli.options[:daemon]
|
17
|
+
# For some reason Celluloid spins threads that break forking
|
18
|
+
# Threads are not shutdown immediately so deamonization will stale until
|
19
|
+
# those threads are killed by Celluloid manager (via timeout)
|
20
|
+
# There's nothing initialized here yet, so instead we shutdown celluloid
|
21
|
+
# and run it again when we need (after fork)
|
22
|
+
Celluloid.shutdown
|
23
|
+
validate!
|
24
|
+
daemonize
|
25
|
+
Celluloid.boot
|
26
|
+
end
|
27
|
+
|
28
|
+
# Remove pidfile on shutdown
|
29
|
+
ObjectSpace.define_finalizer('string', proc { send(:clean) })
|
30
|
+
|
31
|
+
# After we fork, we can boot celluloid again
|
32
|
+
Karafka::Server.run
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Prepare (if not exists) directory for a pidfile and check if there is no running karafka
|
38
|
+
# instance already (and raise error if so)
|
39
|
+
def validate!
|
40
|
+
FileUtils.mkdir_p File.dirname(cli.options[:pid])
|
41
|
+
raise "#{cli.options[:pid]} already exists" if File.exist?(cli.options[:pid])
|
42
|
+
end
|
43
|
+
|
44
|
+
# Detaches current process into background and writes its pidfile
|
45
|
+
def daemonize
|
46
|
+
::Process.daemon(true)
|
47
|
+
File.open(
|
48
|
+
cli.options[:pid],
|
49
|
+
'w'
|
50
|
+
) { |file| file.write(::Process.pid) }
|
51
|
+
end
|
52
|
+
|
53
|
+
# Removes a pidfile (if exist)
|
54
|
+
def clean
|
55
|
+
FileUtils.rm_f(cli.options[:pid])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|