Class: ServiceManager::Service

Inherits:
Object
  • Object
show all
Defined in:
lib/service_manager/service.rb

Defined Under Namespace

Classes: ServiceDidntStart

Constant Summary collapse

CHDIR_SEMAPHORE =
Mutex.new
ANSI_COLOR_RESET =
0

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Service

Returns a new instance of Service.

Raises:

  • (ArgumentError)


11
12
13
14
15
16
17
# File 'lib/service_manager/service.rb', line 11

def initialize(options = {})
  options.each { |k,v| send("#{k}=", v) }
  self.host ||= "localhost"
  self.color ||= ANSI_COLOR_RESET
  self.timeout ||= 30
  raise ArgumentError, "You need to provide a name for this app service" unless name
end

Instance Attribute Details

#colorObject

Returns the value of attribute color.



7
8
9
# File 'lib/service_manager/service.rb', line 7

def color
  @color
end

#cwdObject

Returns the value of attribute cwd.



7
8
9
# File 'lib/service_manager/service.rb', line 7

def cwd
  @cwd
end

#hostObject

Returns the value of attribute host.



7
8
9
# File 'lib/service_manager/service.rb', line 7

def host
  @host
end

#loaded_cueObject

Returns the value of attribute loaded_cue.



7
8
9
# File 'lib/service_manager/service.rb', line 7

def loaded_cue
  @loaded_cue
end

#manage_pid_fileObject

Returns the value of attribute manage_pid_file.



7
8
9
# File 'lib/service_manager/service.rb', line 7

def manage_pid_file
  @manage_pid_file
end

#nameObject

Returns the value of attribute name.



7
8
9
# File 'lib/service_manager/service.rb', line 7

def name
  @name
end

#pid_fileObject

Returns the value of attribute pid_file.



7
8
9
# File 'lib/service_manager/service.rb', line 7

def pid_file
  @pid_file
end

#portObject

Returns the value of attribute port.



7
8
9
# File 'lib/service_manager/service.rb', line 7

def port
  @port
end

#processObject

Returns the value of attribute process.



7
8
9
# File 'lib/service_manager/service.rb', line 7

def process
  @process
end

#reload_uriObject

Returns the value of attribute reload_uri.



7
8
9
# File 'lib/service_manager/service.rb', line 7

def reload_uri
  @reload_uri
end

#start_cmdObject

Returns the value of attribute start_cmd.



7
8
9
# File 'lib/service_manager/service.rb', line 7

def start_cmd
  @start_cmd
end

#timeoutObject

Returns the value of attribute timeout.



7
8
9
# File 'lib/service_manager/service.rb', line 7

def timeout
  @timeout
end

Instance Method Details

#reloadObject

reload the service by hitting the configured reload_url. In this case, the service needs to be a web service, and needs to have an action that you can hit, in test mode, that will cause the process to gracefully reload itself.



88
89
90
91
92
93
94
# File 'lib/service_manager/service.rb', line 88

def reload
  return false unless reload_uri
  puts "Reloading #{colorized_service_name} app by hitting http://#{host}:#{port}#{reload_uri} ..."
  res = Net::HTTP.start(host, port) {|http| http.get(reload_uri) }
  raise("Reloading app #{colorized_service_name} did not return a 200! It returned a #{res.code}. Output:\n#{colorize(res.body)}") unless res.code.to_i == 200
  true
end

#running?Boolean

detects if the service is running on the configured host and port (will return true if we weren’t the ones who started it)

Returns:

  • (Boolean)


97
98
99
100
101
102
103
104
105
# File 'lib/service_manager/service.rb', line 97

def running?
  case
  when pid_file
    running_via_pid_file?
  when port
    TCPSocket.listening_service?(:port => port, :host => host || "127.0.0.1")
  else raise "Service Manager needs to be able to tell if the service is already running or not. You'll need to specify a pid file or a TCP port to check."
  end
end

#server_info_hashObject



23
24
25
# File 'lib/service_manager/service.rb', line 23

def server_info_hash
  {:name => name, :host => host, :port => port, :pid_file => pid_file}
end

#startObject



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/service_manager/service.rb', line 49

def start
  if running?
    puts "Server for #{colorized_service_name} detected as running."
    reload || puts("Reloading not supported.  Any changes made to code for #{colorized_service_name} will not take effect!")
    return false
  end

  CHDIR_SEMAPHORE.synchronize do
    puts "Starting #{colorized_service_name} in #{cwd} with '#{start_cmd}'\n"
    Dir.chdir(cwd) do
      without_bundler_env do
        # system("bash -c set")
        self.process = PTYBackgroundProcess.run(start_cmd)
      end
    end
  end
  at_exit { stop }
  wait
  puts "Server #{colorized_service_name} is up."
  File.open(pid_file, "wb") { |f| f << process.pid } if manage_pid_file
end

#start_output_stream_threadObject



34
35
36
# File 'lib/service_manager/service.rb', line 34

def start_output_stream_thread
  Thread.new { process.detect { |output| STDOUT << colorize(output); nil} }
end

#stopObject

stop the service. If we didn’t start it, do nothing.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/service_manager/service.rb', line 72

def stop
  return unless process
  puts "Shutting down #{colorized_service_name}"
  process.kill
  process.wait(3)
  if process.running?
    process.kill("KILL") # ok... no more Mr. Nice Guy.
    process.wait
  end
  puts "Server #{colorized_service_name} (#{process.pid}) is shut down"
  self.process = nil
  FileUtils.rm(pid_file) if manage_pid_file && File.exist?(pid_file)
  true
end

#urlObject



19
20
21
# File 'lib/service_manager/service.rb', line 19

def url
  "http://#{host}:#{port}"
end

#watch_for_cueObject



27
28
29
30
31
32
# File 'lib/service_manager/service.rb', line 27

def watch_for_cue
  process.detect(:both, timeout) do |output|
    STDOUT << colorize(output)
    output =~ loaded_cue
  end
end

#without_bundler_env(&block) ⇒ Object



42
43
44
45
46
47
# File 'lib/service_manager/service.rb', line 42

def without_bundler_env(&block)
  vars = %w{BUNDLE_PATH BUNDLE_GEMFILE BUNDLE_BIN_PATH}
  old_values = vars.map {|v| ENV.delete(v)}
  yield
  vars.zip(old_values).each { |var, value| ENV[var] = value }
end