karafka 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|