forking 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ log
2
+ TODO
3
+ locks
4
+ *.gem
5
+ *.log
6
+ *.pid
7
+ Gemfile.lock
8
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Makarchev K
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,56 @@
1
+ Forking
2
+ =======
3
+
4
+ Simple processes forking, and restarting. Master process starts as daemon.
5
+
6
+
7
+ $ gem install forking
8
+
9
+
10
+ Example 1.rb (run 5 child processes and capturing logs):
11
+
12
+ ```ruby
13
+ #!/usr/bin/env ruby
14
+ require 'rubygems'
15
+ require 'forking'
16
+
17
+ f = Forking.new(:name => 'test', :working_dir => File.dirname(__FILE__),
18
+ :log_file => "spawner.log", :pid_file => "spawner.pid", :sync_log => true)
19
+
20
+ f.before_fork do
21
+ puts "load env"
22
+ end
23
+
24
+ f.after_fork do
25
+ puts "restart connects"
26
+ end
27
+
28
+ 2.times do |i|
29
+ f.spawn(:name => "test1", :log_file => "test1.log") do
30
+ loop do
31
+ puts "test1 #{i}"
32
+ sleep 1
33
+ end
34
+ end
35
+ end
36
+
37
+ 3.times do |i|
38
+ f.spawn(:log_file => "test2.log", :sync_log => true) do
39
+ exec 'ruby', '2.rb', '--test'
40
+ end
41
+ end
42
+
43
+ f.run!
44
+ ```
45
+
46
+ Usage:
47
+
48
+ $ ./1.rb start
49
+ $ ./1.rb status
50
+ $ ./1.rb stop
51
+ $ ./1.rb restart
52
+
53
+ Respawn childs:
54
+
55
+ $ kill -HUP master_pid
56
+
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'bundler'
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ require 'rspec/core/rake_task'
7
+ task :default => :spec
8
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'bundler/setup'
4
+ require 'forking.rb'
5
+
6
+ f = Forking.new(:name => 'test',
7
+ :working_dir => File.dirname(__FILE__),
8
+ :log_file => "spawner.log",
9
+ :pid_file => "spawner.pid",
10
+ :sync_log => true)
11
+
12
+ f.before_fork do
13
+ puts "before fork"
14
+ end
15
+
16
+ f.after_fork do
17
+ puts "after fork"
18
+ end
19
+
20
+ 2.times do |i|
21
+ f.spawn(:name => "test1", :log_file => "test1.log") do
22
+ $0 = "test1 #{i}"
23
+ loop do
24
+ puts "test1 #{i}"
25
+ sleep 1
26
+ end
27
+ end
28
+ end
29
+
30
+ 3.times do |i|
31
+ f.spawn(:log_file => "test2.log", :sync_log => true) do
32
+ exec 'ruby', '2.rb', '--test', 'some_value'
33
+ end
34
+ end
35
+
36
+ f.run!
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $0 = "test2"
4
+
5
+ loop do
6
+
7
+ p ARGV
8
+ sleep 1
9
+
10
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.dirname(__FILE__) + "/lib/version"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = %q{forking}
6
+ s.version = Forking::VERSION
7
+
8
+ s.authors = ["Makarchev Konstantin"]
9
+
10
+ s.description = %q{Simple processes forking, and restarting. Master process starts as daemon.}
11
+ s.summary = %q{Simple processes forking, and restarting. Master process starts as daemon.}
12
+
13
+ s.email = %q{kostya27@gmail.com}
14
+ s.homepage = %q{http://github.com/kostya/forking}
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'daemon-spawn'
22
+ s.add_development_dependency "rspec"
23
+ s.add_development_dependency "rake"
24
+
25
+ end
@@ -0,0 +1,69 @@
1
+ require 'daemon_spawn' # gem
2
+
3
+ class DaemonSpawnBase < DaemonSpawn::Base
4
+
5
+ def initialize(args)
6
+ GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=)
7
+ @args = args
8
+ @procs = @args[:procs]
9
+ @restart = true
10
+
11
+ super
12
+ end
13
+
14
+ def start(_)
15
+ raise "empty @procs" if !@procs || @procs.empty?
16
+
17
+ # HUP is restart all childs
18
+ trap("HUP") do
19
+ stop_all
20
+ end
21
+
22
+ @args[:before_fork].call if @args[:before_fork]
23
+
24
+ start_all
25
+
26
+ while @restart
27
+ pid = nil
28
+
29
+ begin
30
+ pid = Process.wait
31
+ rescue Errno::ECHILD
32
+ end
33
+
34
+ process = @procs.detect{|p| p.pid == pid }
35
+ puts "#{process.name} had just died!"
36
+
37
+ process.start if @restart
38
+ end
39
+
40
+ rescue
41
+ stop_all
42
+ end
43
+
44
+ def stop
45
+ @restart = false
46
+ stop_all
47
+ end
48
+
49
+ private
50
+
51
+ def start_all
52
+ @procs.each do |process|
53
+ process.start
54
+ end
55
+
56
+ puts "started all (#{@procs.size})!"
57
+ end
58
+
59
+ def stop_all
60
+ return unless @procs
61
+
62
+ @procs.each do |process|
63
+ process.stop
64
+ end
65
+
66
+ puts "stopped all (#{@procs.size})!"
67
+ end
68
+
69
+ end
@@ -0,0 +1,36 @@
1
+ require File.join(File.dirname(__FILE__), 'daemon_spawn_base')
2
+ require File.join(File.dirname(__FILE__), 'mini_process')
3
+
4
+ class Forking
5
+
6
+ # opts:
7
+ # :name
8
+ # :sync_log
9
+ # :log_file
10
+ # :pid_file
11
+ # :working_dir *
12
+
13
+ def initialize(opts = {})
14
+ @opts = opts
15
+ @merge_opts = opts.update(:sync_log => nil) # sync_log should specify for each spawn
16
+ @procs = []
17
+ end
18
+
19
+ def run!
20
+ $0 = "#{@opts[:name]} spawner" unless @opts[:dont_touch_pl]
21
+ DaemonSpawnBase.spawn!(@opts.merge(:procs => @procs, :before_fork => @before_fork, :application => @opts[:name]))
22
+ end
23
+
24
+ def spawn(opts = {}, &block)
25
+ @procs << MiniProcess.new(@merge_opts.merge(opts).merge(:after_fork => @after_fork), &block)
26
+ end
27
+
28
+ def before_fork(&block)
29
+ @before_fork = block
30
+ end
31
+
32
+ def after_fork(&block)
33
+ @after_fork = block
34
+ end
35
+
36
+ end
@@ -0,0 +1,56 @@
1
+ class MiniProcess
2
+ attr_accessor :pid
3
+
4
+ DEFAULT_SLEEP = 0.2
5
+
6
+ # options
7
+ # :name -
8
+ # :sleep - timeout between spawns
9
+ # :log_file -
10
+ # :sync_log -
11
+ # :working_dir - for log
12
+ # :after_fork
13
+
14
+ def initialize(opts = {}, &block)
15
+ @opts = opts
16
+ @block = block
17
+ @opts[:sync_log] ||= true
18
+
19
+ raise "block should be" unless block
20
+ end
21
+
22
+ def start
23
+ GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=)
24
+
25
+ @pid = fork do
26
+ STDIN.reopen("/dev/null")
27
+ log_name = @opts[:log_file] || "/dev/null"
28
+ log_name = File.expand_path(log_name)
29
+ STDOUT.reopen(log_name, "a")
30
+ STDOUT.sync = @opts[:sync_log]
31
+ STDERR.reopen(log_name, "a")
32
+ STDERR.sync = @opts[:sync_log]
33
+ @opts[:after_fork].call if @opts[:after_fork]
34
+ @block.call
35
+ end
36
+
37
+ puts "start process #{name}"
38
+ pause
39
+ @pid
40
+ end
41
+
42
+ def stop
43
+ return unless @pid
44
+ Process.kill("KILL", @pid) rescue nil
45
+ puts "stop #{name}"
46
+ end
47
+
48
+ def pause
49
+ sleep (@opts[:sleep] || DEFAULT_SLEEP).to_f
50
+ end
51
+
52
+ def name
53
+ "#{@opts[:name]}[#{@pid}]"
54
+ end
55
+
56
+ end
@@ -0,0 +1,3 @@
1
+ class Forking
2
+ VERSION = "0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: forking
3
+ version: !ruby/object:Gem::Version
4
+ hash: 9
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ version: "0.1"
10
+ platform: ruby
11
+ authors:
12
+ - Makarchev Konstantin
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2012-06-30 00:00:00 Z
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: daemon-spawn
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 3
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: rspec
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ hash: 3
42
+ segments:
43
+ - 0
44
+ version: "0"
45
+ type: :development
46
+ version_requirements: *id002
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ prerelease: false
50
+ requirement: &id003 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ hash: 3
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ type: :development
60
+ version_requirements: *id003
61
+ description: Simple processes forking, and restarting. Master process starts as daemon.
62
+ email: kostya27@gmail.com
63
+ executables: []
64
+
65
+ extensions: []
66
+
67
+ extra_rdoc_files: []
68
+
69
+ files:
70
+ - .gitignore
71
+ - Gemfile
72
+ - LICENSE
73
+ - README.md
74
+ - Rakefile
75
+ - example/1.rb
76
+ - example/2.rb
77
+ - forking.gemspec
78
+ - lib/daemon_spawn_base.rb
79
+ - lib/forking.rb
80
+ - lib/mini_process.rb
81
+ - lib/version.rb
82
+ homepage: http://github.com/kostya/forking
83
+ licenses: []
84
+
85
+ post_install_message:
86
+ rdoc_options: []
87
+
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ hash: 3
96
+ segments:
97
+ - 0
98
+ version: "0"
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ hash: 3
105
+ segments:
106
+ - 0
107
+ version: "0"
108
+ requirements: []
109
+
110
+ rubyforge_project:
111
+ rubygems_version: 1.8.24
112
+ signing_key:
113
+ specification_version: 3
114
+ summary: Simple processes forking, and restarting. Master process starts as daemon.
115
+ test_files: []
116
+