Class: Redis::SpawnServer

Inherits:
Object
  • Object
show all
Defined in:
lib/redis/spawn.rb,
lib/redis/spawn/version.rb

Constant Summary collapse

VERSION =
"0.1.1"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(supplied_opts = {}) ⇒ SpawnServer

Returns a new instance of SpawnServer.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/redis/spawn.rb', line 71

def initialize(supplied_opts = {})
  default_opts = {
    generated_config_file: "/tmp/redis-spawned.#{Process.pid}.config",
    cleanup_files:         [:socket, :log, :config],
    server_opts:           {},
    start:                 true
  }
  @supplied_opts = supplied_opts
  @opts = default_opts.merge(supplied_opts)
  self.server_opts = opts[:server_opts]
  
  opts[:start] ? self.start : 0

  # Return the instance
  self
end

Instance Attribute Details

#optsObject (readonly)

Returns the value of attribute opts.



69
70
71
# File 'lib/redis/spawn.rb', line 69

def opts
  @opts
end

#pidObject (readonly)

Returns the value of attribute pid.



69
70
71
# File 'lib/redis/spawn.rb', line 69

def pid
  @pid
end

#server_optsObject

Returns the value of attribute server_opts.



69
70
71
# File 'lib/redis/spawn.rb', line 69

def server_opts
  @server_opts
end

#supplied_optsObject (readonly)

Returns the value of attribute supplied_opts.



69
70
71
# File 'lib/redis/spawn.rb', line 69

def supplied_opts
  @supplied_opts
end

Class Method Details

.build_config_line(key, value) ⇒ Object

Build a configuration file line

Parameters:

  • key: (Symbol, String)

    The configuration parameter. Underscores in the key are transposed to dashes

  • value: (String, Object)

    The value to set for this configuration parameter

Returns:

  • A line of Redis server configuration data



54
55
56
# File 'lib/redis/spawn.rb', line 54

def self.build_config_line(key, value)
  key.to_s.gsub(/_/, "-") + " " + value.to_s
end

.default_server_optsObject



38
39
40
# File 'lib/redis/spawn.rb', line 38

def self.default_server_opts
  @_default_server_opts
end

.default_server_opts=(new_defaults_hash) ⇒ Object



42
43
44
# File 'lib/redis/spawn.rb', line 42

def self.default_server_opts=(new_defaults_hash)
  @_default_server_opts = new_defaults_hash
end

.spawn(supplied_opts = {}) ⇒ SpawnServer

Spawn a Redis server configured with the supplied options. By default, the spawned server will be a child of the current process and won’t daemonize (@todo allow daemonization)

Parameters:

  • supplied_opts:

    options for this server including any configuration overrides

Returns:

  • (SpawnServer)

    instance corresponding to the spawned server



65
66
67
# File 'lib/redis/spawn.rb', line 65

def self.spawn(supplied_opts = {})
  self.new(supplied_opts)
end

Instance Method Details

#build_configObject

Build configuration file data

Returns:

  • Redis server compatible configuration file data



185
186
187
188
189
190
191
192
193
194
195
# File 'lib/redis/spawn.rb', line 185

def build_config
  config_data = ""
  self.server_opts.each do |key, value|
    if value.kind_of?(Array)
      value.each { |subvalue| config_data << self.class.build_config_line(key, subvalue) << "\n" }
    else
      config_data << self.class.build_config_line(key, value) << "\n"
    end
  end
  config_data
end

#cleanup_filesObject

Clean up server files associated with this instance. Expects #opts to already be set up



199
200
201
202
203
# File 'lib/redis/spawn.rb', line 199

def cleanup_files
  files_from_symbols(opts[:cleanup_files]) do |file|
    File.exist?(file) && File.delete(file)
  end
end

#files_from_symbols(file_syms) ⇒ Object

Iterates over the supplied symbols and yields corresponding filenames

Parameters:

  • file_syms: (Array)

    array of symbols to iterate over



208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/redis/spawn.rb', line 208

def files_from_symbols(file_syms)
  file_syms.each do |file_sym|
    yield case file_sym
      when :socket
        server_opts[:unixsocket]
      when :log
        server_opts[:logfile]
      when :config
        @config_file || opts[:generated_config_file]
    end
  end
end

#shutdownObject

Shutdown the spawned redis-server if it is running



144
145
146
147
148
149
150
# File 'lib/redis/spawn.rb', line 144

def shutdown
  if self.started?
    self.shutdown!
  else
    nil
  end
end

#shutdown!Object

Forcibly shutdown the spawned redis-server. Used internally by #shutdown.



153
154
155
156
157
158
159
160
161
# File 'lib/redis/spawn.rb', line 153

def shutdown!
  Process.kill("TERM", self.pid)
rescue Errno::ESRCH
  # Already dead - do nothing
  nil
ensure
  @pid = nil
  self.cleanup_files      
end

#socketObject

Shortcut for getting name of the configured unix socket file



222
223
224
# File 'lib/redis/spawn.rb', line 222

def socket
  self.server_opts[:unixsocket]
end

#spawnObject

Spawn a redis server. Only call this function once a config file exists and is specified

Returns:

  • the pid of the spawned server



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/redis/spawn.rb', line 114

def spawn
  # Abort if there's no config file
  unless @config_file && File.exist?(@config_file)
    raise "Config file #{@config_file.inspect} not found"
  end
   
  # Make sure we clean up after our children and avoid a zombie invasion
  trap("CLD") do
    pid = Process.wait(-1, Process::WNOHANG)
  end

  # Start the server
  @pid = fork { exec("redis-server #{@config_file}") }
  #logger.info("Spawned redis server with PID #{pid}")

  at_exit do
    # Maybe make this configurable to allow the server to continue after exit
    self.shutdown!
    Process.wait(@pid,  Process::WNOHANG) if (@pid && @pid != 0)
  end
  
  self.pid
end

#startObject

Prepare a redis configuration file then start the server

Returns:

  • pid of the server



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/redis/spawn.rb', line 91

def start
  # If config_file is passed in opts use it as the name of the config file.
  # Otherwise, generate our own
  @config_file = if opts.has_key?(:config_file)
    # Don't attempt to cleanup files when supplied with pre-existing
    # config file unless specifically asked
    opts[:cleanup_files] = [] unless supplied_opts.has_key?(:cleanup_files)
    opts[:config_file]
  else
    self.write_config
  end
  
  # Ensure the data directory exists
  Dir.exists?(self.server_opts[:dir]) || Dir.mkdir(self.server_opts[:dir])

  # Spawn the redis server for this instance
  self.spawn
end

#started?Boolean

Check whether the server is stated by checking if a value is assigned to @pid

Returns:

  • (Boolean)


139
140
141
# File 'lib/redis/spawn.rb', line 139

def started?
  self.pid ? true : false
end

#write_configObject

Write the Redis configuration file to disk.

Returns:

  • the name of the written file



174
175
176
177
178
179
180
# File 'lib/redis/spawn.rb', line 174

def write_config
  File.open(self.opts[:generated_config_file], "w") do |file|
    ## @todo Migrate class based build_config to instance based build_config
    file.write(self.build_config)
  end
  self.opts[:generated_config_file]
end