seamusabshere-daemon-spawn 0.2.1

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.
data/.autotest ADDED
@@ -0,0 +1,16 @@
1
+ Autotest.add_hook(:initialize) do |at|
2
+ at.clear_mappings
3
+
4
+ at.add_mapping(/.*flymake/) do |f, _|
5
+ []
6
+ end
7
+
8
+ at.add_mapping(%r[lib/daemon-spawn.rb]) do |f, _|
9
+ at.files_matching /^test\/.*_test\.rb$/
10
+ end
11
+
12
+ at.add_mapping(/^test\/.*_test\.rb$/) do |filename, _|
13
+ filename
14
+ end
15
+
16
+ end
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ doc
2
+ pkg
data/History.txt ADDED
@@ -0,0 +1,20 @@
1
+ === 0.3.0 / 2010-04-18
2
+
3
+ * Typo fix and internal refactoring patches from Emmanuel Gomez
4
+ * Added multi-process spawning and management (inspired by Jontathan Tropper's
5
+ patches)
6
+ * Added LSB-compliance patches from Woody Peterson
7
+ * Added some actual test-coverage :-P
8
+ * Moved examples from "examples" directory to "test/servers"
9
+
10
+ === 0.2.0 / 2009-04-22
11
+
12
+ * Allow specification of args instead of ARGV so that scripts can
13
+ handle command line parsing and validation prior to spawning.
14
+
15
+ === 0.1.0 / 2009-01-26
16
+
17
+ * 1 major enhancement
18
+
19
+ * Happy Birthday!
20
+
data/Manifest.txt ADDED
@@ -0,0 +1,9 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/daemon_spawn.rb
6
+ test/daemon_spawn_test.rb
7
+ test/multi_daemon_spawn_test.rb
8
+ test/servers/echo_server.rb
9
+ test/servers/simple_server.rb
data/README.txt ADDED
@@ -0,0 +1,107 @@
1
+ = daemon-spawn
2
+
3
+ * http://github.com/alexvollmer/daemon-spawn
4
+
5
+ == DESCRIPTION:
6
+
7
+ Daemon launching and management made dead simple.
8
+
9
+ With daemon-spawn you can start, stop and restart processes that run
10
+ in the background. Processed are tracked by a simple PID file written
11
+ to disk.
12
+
13
+ In addition, you can choose to either execute ruby in your daemonized
14
+ process or 'exec' another process altogether (handy for wrapping other
15
+ services).
16
+
17
+ == SYNOPSIS:
18
+
19
+ === WRITING A DAEMON:
20
+
21
+ To create a new spawner, write a class that extends <tt>DaemonSpawn::Base</tt>
22
+ and provides +start+ and +stop+ methods. For example:
23
+
24
+ class MyServer < DaemonSpawn::Base
25
+
26
+ def start(args)
27
+ # process command-line args
28
+ # start your bad self
29
+ end
30
+
31
+ def stop
32
+ # stop your bad self
33
+ end
34
+ end
35
+
36
+ MyServer.spawn!(:log_file => '/var/log/echo_server.log',
37
+ :pid_file => '/var/run/echo_server.pid',
38
+ :sync_log => true,
39
+ :working_dir => File.dirname(__FILE__))
40
+
41
+ If you need command-line parameters, any arguments passed after one of
42
+ the commands (start, stop, status or restart) will be passed to the
43
+ +start+ method.
44
+
45
+ The <tt>spawn!</tt> method takes a hash of symbolized keys. At a minimum you
46
+ _must_ specify the <tt>:working_dir</tt> option. You can also override
47
+ the default locations for the log and PID files.
48
+
49
+ If you pass a <tt>:processes</tt> option to the <tt>spawn!</tt>,
50
+ daemon spawn will start that number of processes.
51
+
52
+ See the <tt>test/servers</tt> directory for working examples.
53
+
54
+ === RUNNING A DAEMON:
55
+
56
+ Let's say that you have the example script listed above in
57
+ <tt>bin/my_server</tt>. Here are the commands for starting, querying
58
+ the status, restarting and stopping the daemon:
59
+
60
+ bin/my_server start
61
+ bin/my_server status
62
+ bin/my_server restart
63
+ bin/my_server stop
64
+
65
+ Note that if any additional arguments are passed to either
66
+ <tt>start</tt> or <tt>restart</tt> those will be passed to the +start+
67
+ method of an instance of your daemon class.
68
+
69
+
70
+ == REQUIREMENTS:
71
+
72
+ None!
73
+
74
+ == CONTRIBUTIONS:
75
+
76
+ Feel free to fork this project and send me pull requests with any
77
+ changes that you have. Please note that I won't accept any patches
78
+ with significant formatting changes or ones without tests.
79
+
80
+ == INSTALL:
81
+
82
+ * sudo gem install daemon-spawn
83
+
84
+ == LICENSE:
85
+
86
+ (The MIT License)
87
+
88
+ Copyright (c) 2009 Evri, Inc.
89
+
90
+ Permission is hereby granted, free of charge, to any person obtaining
91
+ a copy of this software and associated documentation files (the
92
+ 'Software'), to deal in the Software without restriction, including
93
+ without limitation the rights to use, copy, modify, merge, publish,
94
+ distribute, sublicense, and/or sell copies of the Software, and to
95
+ permit persons to whom the Software is furnished to do so, subject to
96
+ the following conditions:
97
+
98
+ The above copyright notice and this permission notice shall be
99
+ included in all copies or substantial portions of the Software.
100
+
101
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
102
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
103
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
104
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
105
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
106
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
107
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ # -*- ruby -*-
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |gemspec|
6
+ gemspec.name = "seamusabshere-daemon-spawn"
7
+ gemspec.summary = "A simple, flexible daemon management library. (re-released by Seamus Abshere)"
8
+ gemspec.description = %{gem 0.3.0 re-release... originally at http://github.com/alexvollmer/daemon-spawn}
9
+ gemspec.email = "seamus@abshere.net"
10
+ gemspec.homepage = "http://github.com/seamusabshere/daemon-spawn"
11
+ gemspec.authors = ["Alex Vollmer"]
12
+ end
13
+ Jeweler::GemcutterTasks.new
14
+ rescue LoadError
15
+ puts "Jeweler not available. Install it with: gem install jeweler"
16
+ end
17
+
18
+ # vim: syntax=Ruby
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.1
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{daemon-spawn}
5
+ s.version = "0.2.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Alex Vollmer"]
9
+ s.date = %q{2009-09-21}
10
+ s.description = %q{Daemon launching and management made dead simple.
11
+
12
+ With daemon-spawn you can start, stop and restart processes that run
13
+ in the background. Processed are tracked by a simple PID file written
14
+ to disk.
15
+
16
+ In addition, you can choose to either execute ruby in your daemonized
17
+ process or 'exec' another process altogether (handy for wrapping other
18
+ services).}
19
+ s.email = ["alex.vollmer@gmail.com"]
20
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
21
+ s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "lib/daemon-spawn.rb", "test/test_daemon-spawn.rb", "examples/echo_server.rb"]
22
+ s.homepage = %q{http://github.com/alexvollmer/daemon-spawn}
23
+ s.rdoc_options = ["--main", "README.txt"]
24
+ s.require_paths = ["lib"]
25
+ s.rubyforge_project = %q{daemon-spawn}
26
+ s.rubygems_version = %q{1.3.5}
27
+ s.summary = %q{Daemon launching and management made dead simple}
28
+ s.test_files = ["test/test_daemon-spawn.rb"]
29
+
30
+ if s.respond_to? :specification_version then
31
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
32
+ s.specification_version = 3
33
+
34
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
35
+ s.add_development_dependency(%q<hoe>, [">= 2.3.3"])
36
+ else
37
+ s.add_dependency(%q<hoe>, [">= 2.3.3"])
38
+ end
39
+ else
40
+ s.add_dependency(%q<hoe>, [">= 2.3.3"])
41
+ end
42
+ end
@@ -0,0 +1,197 @@
1
+ require 'fileutils'
2
+
3
+ # Large portions of this were liberally stolen from the
4
+ # 'simple-daemon' project at http://simple-daemon.rubyforge.org/
5
+ module DaemonSpawn
6
+ VERSION = '0.3.0'
7
+
8
+ def self.usage(msg=nil) #:nodoc:
9
+ print "#{msg}, " if msg
10
+ puts "usage: #{$0} <command> [options]"
11
+ puts "Where <command> is one of start, stop, restart or status"
12
+ puts "[options] are additional options passed to the underlying process"
13
+ end
14
+
15
+ def self.start(daemon, args) #:nodoc:
16
+ if !File.writable?(File.dirname(daemon.log_file))
17
+ STDERR.puts "Unable to write log file to #{daemon.log_file}"
18
+ exit 1
19
+ end
20
+
21
+ if !File.writable?(File.dirname(daemon.pid_file))
22
+ STDERR.puts "Unable to write PID file to #{daemon.pid_file}"
23
+ exit 1
24
+ end
25
+
26
+ if daemon.alive? && daemon.singleton
27
+ STDERR.puts "An instance of #{daemon.app_name} is already " +
28
+ "running (PID #{daemon.pid})"
29
+ exit 0
30
+ end
31
+
32
+ fork do
33
+ Process.setsid
34
+ exit if fork
35
+ open(daemon.pid_file, 'w') { |f| f << Process.pid }
36
+ Dir.chdir daemon.working_dir
37
+ File.umask 0000
38
+ log = File.new(daemon.log_file, "a")
39
+ log.sync = daemon.sync_log
40
+ STDIN.reopen "/dev/null"
41
+ STDOUT.reopen log
42
+ STDERR.reopen STDOUT
43
+ trap("TERM") {daemon.stop; exit}
44
+ daemon.start(args)
45
+ end
46
+ puts "#{daemon.app_name} started."
47
+ end
48
+
49
+ def self.stop(daemon) #:nodoc:
50
+ if pid = daemon.pid
51
+ FileUtils.rm(daemon.pid_file)
52
+ Process.kill("TERM", pid)
53
+ begin
54
+ Process.wait(pid)
55
+ rescue Errno::ECHILD
56
+ end
57
+ else
58
+ puts "PID file not found. Is the daemon started?"
59
+ end
60
+ rescue Errno::ESRCH
61
+ puts "PID file found, but process was not running. The daemon may have died."
62
+ end
63
+
64
+ def self.status(daemon) #:nodoc:
65
+ puts "#{daemon.app_name} is #{daemon.alive? ? "" : "NOT "}running (PID #{daemon.pid})"
66
+ end
67
+
68
+ class Base
69
+ attr_accessor :log_file, :pid_file, :sync_log, :working_dir, :app_name, :singleton, :index
70
+
71
+ def initialize(opts = {})
72
+ raise 'You must specify a :working_dir' unless opts[:working_dir]
73
+ self.working_dir = opts[:working_dir]
74
+ self.app_name = opts[:application] || classname
75
+ self.pid_file = opts[:pid_file] || File.join(working_dir, 'tmp', 'pids', app_name + extension)
76
+ self.log_file = opts[:log_file] || File.join(working_dir, 'logs', app_name + '.log')
77
+ self.index = opts[:index] || 0
78
+ if self.index > 0
79
+ self.pid_file += ".#{self.index}"
80
+ self.log_file += ".#{self.index}"
81
+ end
82
+ self.sync_log = opts[:sync_log]
83
+ self.singleton = opts[:singleton] || false
84
+ end
85
+
86
+ def classname #:nodoc:
87
+ self.class.to_s.split('::').last
88
+ end
89
+
90
+ # Provide your implementation. These are provided as a reminder
91
+ # only and will raise an error if invoked. When started, this
92
+ # method will be invoked with the remaining command-line arguments.
93
+ def start(args)
94
+ raise "You must implement a 'start' method in your class!"
95
+ end
96
+
97
+ # Provide your implementation. These are provided as a reminder
98
+ # only and will raise an error if invoked.
99
+ def stop
100
+ raise "You must implement a 'stop' method in your class!"
101
+ end
102
+
103
+ def alive? #:nodoc:
104
+ if File.file?(self.pid_file)
105
+ begin
106
+ Process.kill(0, self.pid)
107
+ rescue Errno::ESRCH, ::Exception
108
+ false
109
+ end
110
+ else
111
+ false
112
+ end
113
+ end
114
+
115
+ def pid #:nodoc:
116
+ IO.read(self.pid_file).to_i rescue nil
117
+ end
118
+
119
+ def self.build(options)
120
+ count = options.delete(:processes) || 1
121
+ daemons = []
122
+ count.times do |index|
123
+ daemons << new(options.merge(:index => index))
124
+ end
125
+ daemons
126
+ end
127
+
128
+ def self.find(options)
129
+ pid_file = new(options).pid_file
130
+ basename = File.basename(pid_file).split('.').first
131
+ pid_files = Dir.glob(File.join(File.dirname(pid_file), "#{basename}.*pid*"))
132
+ pid_files.map { |f| new(options.merge(:pid_file => f)) }
133
+ end
134
+
135
+ # Invoke this method to process command-line args and dispatch
136
+ # appropriately. Valid options include the following _symbols_:
137
+ # - <tt>:working_dir</tt> -- the working directory (required)
138
+ # - <tt>:log_file</tt> -- path to the log file
139
+ # - <tt>:pid_file</tt> -- path to the pid file
140
+ # - <tt>:sync_log</tt> -- indicate whether or not to sync log IO
141
+ # - <tt>:singleton</tt> -- If set to true, only one instance is
142
+ # allowed to start
143
+ # args must begin with 'start', 'stop', 'status', or 'restart'.
144
+ # The first token will be removed and any remaining arguments
145
+ # passed to the daemon's start method.
146
+ def self.spawn!(opts = {}, args = ARGV)
147
+ case args.any? and command = args.shift
148
+ when 'start', 'stop', 'status', 'restart'
149
+ send(command, opts, args)
150
+ when '-h', '--help', 'help'
151
+ DaemonSpawn.usage
152
+ exit
153
+ else
154
+ DaemonSpawn.usage "Invalid command"
155
+ exit 1
156
+ end
157
+ end
158
+
159
+ def self.start(opts, args)
160
+ daemons = find(opts)
161
+ if daemons.empty?
162
+ daemons = build(opts)
163
+ daemons.map { |d| DaemonSpawn.start(d, args) }
164
+ else
165
+ puts "Daemons already started! PIDS: #{daemons.map {|d| d.pid}.join(', ')}"
166
+ exit 1
167
+ end
168
+ end
169
+
170
+ def self.stop(opts, args)
171
+ daemons = find(opts)
172
+ if daemons.empty?
173
+ puts "No PID files found. Is the daemon started?"
174
+ exit 1
175
+ else
176
+ daemons.each { |d| DaemonSpawn.stop(d) }
177
+ end
178
+ end
179
+
180
+ def self.status(opts, args)
181
+ daemons = find(opts)
182
+ if daemons.empty?
183
+ puts 'No PIDs found'
184
+ else
185
+ daemons.each { |d| DaemonSpawn.status(d) }
186
+ end
187
+ end
188
+
189
+ def self.restart(opts, args)
190
+ daemons = find(opts)
191
+ daemons.map do |daemon|
192
+ DaemonSpawn.stop(daemon)
193
+ DaemonSpawn.start(daemon, args)
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,102 @@
1
+ require "socket"
2
+ require "test/unit"
3
+
4
+ class DaemonSpawnTest < Test::Unit::TestCase
5
+
6
+ SERVERS = File.join(File.dirname(__FILE__), "servers")
7
+
8
+ def with_socket
9
+ socket = TCPSocket.new('localhost', 5150)
10
+ socket.setsockopt(Socket::SOL_SOCKET,
11
+ Socket::SO_RCVTIMEO,
12
+ [1, 0].pack("l_2"))
13
+
14
+ begin
15
+ yield(socket) if block_given?
16
+ ensure
17
+ socket.close
18
+ end
19
+ end
20
+
21
+ def echo_server(*args)
22
+ `./echo_server.rb #{args.join(' ')}`
23
+ end
24
+
25
+ def while_running
26
+ Dir.chdir(SERVERS) do
27
+ `./echo_server.rb stop`
28
+ assert_match(/EchoServer started./, `./echo_server.rb start 5150`)
29
+ sleep 1
30
+ begin
31
+ with_socket
32
+ ensure
33
+ assert_match(//, `./echo_server.rb stop`)
34
+ assert_raises(Errno::ECONNREFUSED) { TCPSocket.new('localhost', 5150) }
35
+ end
36
+ end
37
+ end
38
+
39
+ def test_daemon_running
40
+ while_running do |socket|
41
+ socket << "foobar\n"
42
+ assert_equal "foobar\n", socket.readline
43
+ end
44
+ end
45
+
46
+ def test_status_running
47
+ while_running do |socket|
48
+ assert_match(/EchoServer is running/, `./echo_server.rb status`)
49
+ end
50
+ end
51
+
52
+ def test_status_not_running
53
+ Dir.chdir(SERVERS) do
54
+ assert_match(/No PIDs found/, `./echo_server.rb status`)
55
+ end
56
+ end
57
+
58
+ def test_start_after_started
59
+ while_running do
60
+ pid = echo_server("status").match(/PID (\d+)/)[1]
61
+ assert_match(/Daemons already started! PIDS: #{pid}/,
62
+ echo_server("start"))
63
+ end
64
+ end
65
+
66
+ def test_stop_after_stopped
67
+ Dir.chdir(SERVERS) do
68
+ assert_match("No PID files found. Is the daemon started?",
69
+ `./echo_server.rb stop`)
70
+ end
71
+ end
72
+
73
+ def test_restart_after_stopped
74
+ Dir.chdir(SERVERS) do
75
+ assert_match(/EchoServer started/, `./echo_server.rb restart 5150`)
76
+ assert_equal(0, $?.exitstatus)
77
+ sleep 1
78
+ with_socket do |socket|
79
+ socket << "foobar\n"
80
+ assert_equal "foobar\n", socket.readline
81
+ end
82
+ end
83
+ end
84
+
85
+ def test_restart_after_started
86
+ Dir.chdir(SERVERS) do
87
+ assert_match(/EchoServer started/, `./echo_server.rb start 5150`)
88
+ assert_equal(0, $?.exitstatus)
89
+ sleep 1
90
+
91
+ assert_match(/EchoServer started/, `./echo_server.rb restart 5150`)
92
+ assert_equal(0, $?.exitstatus)
93
+ sleep 1
94
+
95
+ with_socket do |socket|
96
+ socket << "foobar\n"
97
+ assert_equal "foobar\n", socket.readline
98
+ end
99
+ end
100
+ end
101
+
102
+ end
@@ -0,0 +1,111 @@
1
+ require "test/unit"
2
+ require "tempfile"
3
+
4
+ class MultiDaemonSpawnTest < Test::Unit::TestCase
5
+
6
+ SERVERS = File.join(File.dirname(__FILE__), "servers")
7
+
8
+ def setup
9
+ @tmpfile = Tempfile.new("multi_daemon_spawn_test")
10
+ end
11
+
12
+ def tear_down
13
+ @tmpfile.delete
14
+ end
15
+
16
+ def simple_server(*args)
17
+ `./simple_server.rb #{args.join(" ")}`
18
+ end
19
+
20
+ def current_pids
21
+ regexp = /SimpleServer is running \(PID (\d+)\)/
22
+ pids = simple_server("status").split("\n").map do |line|
23
+ if m = regexp.match(line)
24
+ m[1]
25
+ else
26
+ nil
27
+ end
28
+ end.compact
29
+ end
30
+
31
+ def while_running
32
+ Dir.chdir(SERVERS) do
33
+ simple_server "stop"
34
+ simple_server "start", @tmpfile.path
35
+ sleep 1
36
+ begin
37
+ yield if block_given?
38
+ ensure
39
+ simple_server "stop"
40
+ end
41
+ end
42
+ end
43
+
44
+ def test_start_multiple
45
+ while_running do
46
+ lines = open(@tmpfile.path).readlines
47
+ assert_equal 2, lines.size
48
+ assert lines.member?("SimpleServer (0) started\n")
49
+ assert lines.member?("SimpleServer (1) started\n")
50
+ end
51
+ end
52
+
53
+ def test_status_multiple
54
+ while_running do
55
+ lines = simple_server("status").split("\n")
56
+ lines.each do |line|
57
+ assert_match /SimpleServer is running/, line
58
+ end
59
+ end
60
+ end
61
+
62
+ def test_stop_multiple
63
+ while_running
64
+ Dir.chdir(SERVERS) do
65
+ assert_match /No PIDs found/, simple_server("status")
66
+ end
67
+ end
68
+
69
+ def test_restart_multiple
70
+ while_running do
71
+ pids = current_pids
72
+ simple_server "restart"
73
+ new_pids = current_pids
74
+ assert_not_equal pids.sort, new_pids.sort
75
+ end
76
+ end
77
+
78
+ def test_status_with_one_dead_process
79
+ while_running do
80
+ pids = current_pids
81
+ Process.kill(9, pids[0].to_i)
82
+
83
+ lines = simple_server("status").split("\n")
84
+ assert_equal 2, lines.size
85
+ assert lines.member?("SimpleServer is NOT running (PID #{pids[0]})")
86
+ assert lines.member?("SimpleServer is running (PID #{pids[1]})")
87
+ end
88
+ end
89
+
90
+ def test_restart_with_one_dead_process
91
+ while_running do
92
+ pids = current_pids
93
+ Process.kill(9, pids[0].to_i)
94
+
95
+ lines = simple_server("restart").split("\n")
96
+ assert lines.member?("PID file found, but process was not running. The daemon may have died."), lines.inspect
97
+ assert_equal 2, lines.select { |l| l == "SimpleServer started." }.size
98
+
99
+ new_pids = current_pids
100
+ assert_not_equal new_pids, pids
101
+ end
102
+ end
103
+
104
+ def test_start_after_started
105
+ while_running do
106
+ pids = current_pids
107
+ assert_match(/Daemons already started! PIDS: #{pids.join(', ')}/,
108
+ simple_server("start"))
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), "..", "..", "lib"))
4
+
5
+ require "daemon_spawn"
6
+ require "socket"
7
+
8
+ # An echo server using daemon-spawn. It starts up local TCP server
9
+ # socket and repeats each line it receives on the connection. To fire
10
+ # it up run:
11
+ # ./echo_server.rb start 12345
12
+ # Then connect to it using telnet to test it:
13
+ # telnet localhost 12345
14
+ # > howdy!
15
+ # howdy!
16
+ # to shut the daemon down, go back to the command-line and run:
17
+ # ./echo_server.rb stop
18
+ class EchoServer < DaemonSpawn::Base
19
+
20
+ attr_accessor :server_socket
21
+
22
+ def start(args)
23
+ port = args.empty? ? 0 : args.first.to_i
24
+ self.server_socket = TCPServer.new('127.0.0.1', port)
25
+ self.server_socket.setsockopt(Socket::SOL_SOCKET,
26
+ Socket::SO_REUSEADDR,
27
+ true)
28
+ port = self.server_socket.addr[1]
29
+ puts "EchoServer started on port #{port}"
30
+ loop do
31
+ begin
32
+ client = self.server_socket.accept
33
+ puts "Got a connection from #{client}"
34
+ while str = client.gets
35
+ client.write(str)
36
+ puts "Echoed '#{str}' to #{client}"
37
+ end
38
+ rescue Errno::ECONNRESET => e
39
+ STDERR.puts "Client reset connection"
40
+ end
41
+ end
42
+ end
43
+
44
+ def stop
45
+ puts "Stopping EchoServer..."
46
+ self.server_socket.close if self.server_socket
47
+ end
48
+ end
49
+
50
+ EchoServer.spawn!(:working_dir => File.join(File.dirname(__FILE__), '..', '..'),
51
+ :log_file => '/tmp/echo_server.log',
52
+ :pid_file => '/tmp/echo_server.pid',
53
+ :sync_log => true,
54
+ :singleton => true)
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join(File.dirname(__FILE__), "..", "..", "lib"))
4
+
5
+ require "daemon_spawn"
6
+
7
+ class SimpleServer < DaemonSpawn::Base
8
+
9
+ attr_accessor :outfile
10
+
11
+ def start(args)
12
+ abort "USAGE: phrase_server.rb LOGFILE" if args.empty?
13
+ @outfile = args.first
14
+ self.puts "SimpleServer (#{self.index}) started"
15
+ while true # keep running like a real daemon
16
+ sleep 5
17
+ end
18
+ end
19
+
20
+ def puts(str)
21
+ open(@outfile, "a") { |f| f.puts str }
22
+ end
23
+
24
+ def stop
25
+ self.puts "SimpleServer (#{self.index}) stopped"
26
+ end
27
+
28
+ end
29
+
30
+ SimpleServer.spawn!(:working_dir => File.join(File.dirname(__FILE__), '..', '..'),
31
+ :log_file => '/tmp/simple_server.log',
32
+ :pid_file => '/tmp/simple_server.pid',
33
+ :sync_log => true,
34
+ :processes => 2)
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: seamusabshere-daemon-spawn
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 2
8
+ - 1
9
+ version: 0.2.1
10
+ platform: ruby
11
+ authors:
12
+ - Alex Vollmer
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-20 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: gem 0.3.0 re-release... originally at http://github.com/alexvollmer/daemon-spawn
22
+ email: seamus@abshere.net
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.txt
29
+ files:
30
+ - .autotest
31
+ - .gitignore
32
+ - History.txt
33
+ - Manifest.txt
34
+ - README.txt
35
+ - Rakefile
36
+ - VERSION
37
+ - daemon-spawn.gemspec
38
+ - lib/daemon_spawn.rb
39
+ - test/daemon_spawn_test.rb
40
+ - test/multi_daemon_spawn_test.rb
41
+ - test/servers/echo_server.rb
42
+ - test/servers/simple_server.rb
43
+ has_rdoc: true
44
+ homepage: http://github.com/seamusabshere/daemon-spawn
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --charset=UTF-8
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.3.6
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: A simple, flexible daemon management library. (re-released by Seamus Abshere)
73
+ test_files:
74
+ - test/daemon_spawn_test.rb
75
+ - test/multi_daemon_spawn_test.rb
76
+ - test/servers/echo_server.rb
77
+ - test/servers/simple_server.rb