Class: Picky::Interfaces::LiveParameters::MasterChild

Inherits:
Object
  • Object
show all
Defined in:
lib/picky/interfaces/live_parameters/master_child.rb

Overview

This is an interface that provides the user of Picky with the possibility to change parameters while the Application is running.

Direct Known Subclasses

Unicorn

Defined Under Namespace

Classes: CouldNotUpdateConfigurationError

Instance Method Summary collapse

Constructor Details

#initializeMasterChild

Returns a new instance of MasterChild.



16
17
18
19
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 16

def initialize
  @child, @parent = IO.pipe
  start_master_process_thread
end

Instance Method Details

#close_childObject

Close the child if it isn’t yet closed.



96
97
98
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 96

def close_child
  @child.close unless @child.closed?
end

#extract_configurationObject



125
126
127
128
129
130
131
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 125

def extract_configuration
  {
    querying_removes_characters: querying_removes_characters,
    querying_stopwords:          querying_stopwords,
    querying_splits_text_on:     querying_splits_text_on
  }
end

#harakiriObject

Kills itself, but still answering the request honorably.



84
85
86
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 84

def harakiri
  Process.kill :QUIT, Process.pid
end

#kill_each_worker_except(pid) ⇒ Object

Taken from Unicorn.



45
46
47
48
49
50
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 45

def kill_each_worker_except pid
  worker_pids.each do |wpid|
    next if wpid == pid
    kill_worker :KILL, wpid
  end
end

#kill_worker(signal, wpid) ⇒ Object



51
52
53
54
55
56
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 51

def kill_worker signal, wpid
  Process.kill signal, wpid
  exclaim "Killing worker ##{wpid} with signal #{signal}."
rescue Errno::ESRCH
  remove_worker wpid
end

#parameters(configuration_hash) ⇒ Object

Updates any parameters with the ones given and returns the updated params.

The params are a strictly defined hash of:

* querying_removes_characters: Regexp
* querying_stopwords:          Regexp
* querying_splits_text_on:     Regexp

This first tries to update in the child process, and if successful, in the parent process



69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 69

def parameters configuration_hash
  close_child
  exclaim "Trying to update worker child configuration." unless configuration_hash.empty?
  try_updating_configuration_with configuration_hash
  write_parent configuration_hash
  extract_configuration
rescue CouldNotUpdateConfigurationError => e
  # I need to die such that my broken config is never used.
  #
  exclaim "Child process #{Process.pid} performs harakiri because of broken config."
  harakiri
  { e.config_key => :ERROR }
end

#querying_removes_charactersObject

THINK What to do about this? Standardize the tokenizer interface, then access each individual tokenizer.



136
137
138
139
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 136

def querying_removes_characters
  regexp = Tokenizer.searching.instance_variable_get :@removes_characters_regexp
  regexp && regexp.source
end

#querying_removes_characters=(new_value) ⇒ Object



140
141
142
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 140

def querying_removes_characters= new_value
  Tokenizer.searching.removes_characters %r{#{new_value}}
end

#querying_splits_text_onObject



150
151
152
153
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 150

def querying_splits_text_on
  splits = Tokenizer.searching.instance_variable_get :@splits_text_on
  splits && splits.respond_to?(:source) ? splits.source : splits
end

#querying_splits_text_on=(new_value) ⇒ Object



154
155
156
157
158
159
160
161
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 154

def querying_splits_text_on= new_value
  splits = Tokenizer.searching.instance_variable_get :@splits_text_on
  if splits.respond_to?(:source)
    Tokenizer.searching.instance_variable_set(:@splits_text_on, %r{#{new_value}})
  else
    Tokenizer.searching.instance_variable_set(:@splits_text_on, new_value)
  end
end

#querying_stopwordsObject



143
144
145
146
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 143

def querying_stopwords
  regexp = Tokenizer.searching.instance_variable_get :@remove_stopwords_regexp
  regexp && regexp.source
end

#querying_stopwords=(new_value) ⇒ Object



147
148
149
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 147

def querying_stopwords= new_value
  Tokenizer.searching.instance_variable_set(:@remove_stopwords_regexp, %r{#{new_value}})
end

#start_master_process_threadObject

This runs a thread that listens to child processes.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 23

def start_master_process_thread
  # This thread is stopped in the children.
  #
  Thread.new do
    loop do
      IO.select([@child], nil, nil, 2) or next
      result = @child.gets ';;;'
      pid, configuration_hash = eval result
      next unless Hash === configuration_hash
      next if configuration_hash.empty?
      exclaim "Trying to update MASTER configuration."
      try_updating_configuration_with configuration_hash
      kill_each_worker_except pid

      # Fails hard on an error.
      #
    end
  end
end

#to_sObject



165
166
167
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 165

def to_s
  "Suckerfish Live Interface (Use the picky-live gem to introspect)"
end

#try_updating_configuration_with(configuration_hash) ⇒ Object

Tries updating the configuration in the child process or parent process.



110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 110

def try_updating_configuration_with configuration_hash
  current_key = nil
  begin
    configuration_hash.each_pair do |key, new_value|
      exclaim "  Setting #{key} with #{new_value}."
      current_key = key
      send :"#{key}=", new_value
    end
  rescue StandardError => e
    # Catch any error and reraise as config error.
    #
    raise CouldNotUpdateConfigurationError.new current_key, e.message
  end
end

#write_parent(configuration_hash) ⇒ Object

Write the parent.

Note: The ;;; is the end marker for the message.



91
92
93
# File 'lib/picky/interfaces/live_parameters/master_child.rb', line 91

def write_parent configuration_hash
  @parent.write "#{[Process.pid, configuration_hash]};;;"
end