acpc_table_manager 1.0.9 → 2.0.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c92fc6d2b98a660e84a1c35388a611ea823e1aff
4
- data.tar.gz: ca8cf252e3be0b58f38eae14b5473e7fc03eb717
3
+ metadata.gz: e5d135a405ab862b042bc72b5bc5f9171e3bd0ed
4
+ data.tar.gz: 0ee34a84a44f500946fdab2e8b08945b0ce09366
5
5
  SHA512:
6
- metadata.gz: 19bb3dcdffa38b0569a6f3634a3e7010783f9022867bbf589c778ea89d17f427b0b3a3f877295bd914437b884af637791dc741da51832ed6e6106589f10f6c5c
7
- data.tar.gz: 39be21a03b63c06f4124df18bb2e009557d7208e3fb53d234fae85800ca0fba148c357f2b17c897306e3a63f86daf9587cbcb42a7fdcb40733e322ff0ede65e7
6
+ metadata.gz: 8c0d1bee251f1d5bc040c6feb568cc278ef5fcbef42f020199ab5dea64ebb89c0a92ed7e440ffa6a67a210da187d1e4810ac7fb849e063803b5bc1bd40877d8d
7
+ data.tar.gz: a13cab8ef8c26b889577d05094bed698b00ceca9f02bba5b34c137f8fe73dd2534ffdefd2dd0d8e4e4c835905753a975d00862c9d3db36733aff9bf1b1fb2812
@@ -44,8 +44,12 @@ unless match.running? && !match.finished?
44
44
  raise OptionParser::ArgumentError.new("Match \"#{options[:match_id]}\" is not running or has already finished.")
45
45
  end
46
46
 
47
+ Signal.trap("INT") { exit }
48
+ Signal.trap("TERM") { exit }
49
+
47
50
  begin
48
51
  proxy = AcpcTableManager::Proxy.start match
52
+ proxy.log __method__, options
49
53
  loop do
50
54
  message = AcpcTableManager.redis.blpop(
51
55
  "#{AcpcTableManager.config.player_action_channel_prefix}#{options[:match_id]}",
@@ -78,5 +82,5 @@ rescue => e
78
82
  },
79
83
  Logger::Severity::ERROR
80
84
  )
81
- Rusen.notify e # Send an email notification
85
+ AcpcTableManager.notify e # Send an email notification
82
86
  end
@@ -30,6 +30,10 @@ CONFIG_FILE = options[:table_manager_config]
30
30
 
31
31
  AcpcTableManager.load! CONFIG_FILE
32
32
  table_manager = AcpcTableManager::Maintainer.new
33
+
34
+ Signal.trap("INT") { exit }
35
+ Signal.trap("TERM") { exit }
36
+
33
37
  loop do
34
38
  begin
35
39
  message = AcpcTableManager.redis.blpop("table-manager", :timeout => AcpcTableManager.config.maintenance_interval_s)
@@ -64,6 +68,6 @@ loop do
64
68
  },
65
69
  Logger::Severity::ERROR
66
70
  )
67
- Rusen.notify e # Send an email notification
71
+ AcpcTableManager.notify e
68
72
  end
69
73
  end
@@ -1,6 +1,7 @@
1
1
  require 'socket'
2
2
  require 'json'
3
3
  require 'mongoid'
4
+ require 'moped'
4
5
  require 'rusen'
5
6
  require 'contextual_exceptions'
6
7
  require 'acpc_dealer'
@@ -18,9 +19,9 @@ module AcpcTableManager
18
19
  THIS_MACHINE = Socket.gethostname
19
20
  DEALER_HOST = THIS_MACHINE
20
21
 
21
- attr_reader :file, :log_directory, :my_log_directory, :match_log_directory
22
+ attr_reader :file, :log_directory, :my_log_directory, :match_log_directory, :proxy_pids_file
22
23
 
23
- def initialize(file_path, log_directory_, match_log_directory_, interpolation_hash)
24
+ def initialize(file_path, log_directory_, match_log_directory_, proxy_pids_file_, interpolation_hash)
24
25
  @file = file_path
25
26
  JSON.parse(File.read(file_path)).each do |constant, val|
26
27
  define_singleton_method(constant.to_sym) do
@@ -30,6 +31,7 @@ module AcpcTableManager
30
31
  @log_directory = log_directory_
31
32
  @match_log_directory = match_log_directory_
32
33
  @my_log_directory = File.join(@log_directory, 'acpc_table_manager')
34
+ @proxy_pids_file = proxy_pids_file_
33
35
  @logger = Logger.from_file_name(File.join(@my_log_directory, 'config.log'))
34
36
  end
35
37
 
@@ -124,6 +126,9 @@ module AcpcTableManager
124
126
  @@config_file = nil
125
127
  def self.config_file() @@config_file end
126
128
 
129
+ @@notifier = nil
130
+ def self.notifier() @@notifier end
131
+
127
132
  def self.load_config!(config_data, yaml_directory = File.pwd)
128
133
  interpolation_hash = {
129
134
  pwd: yaml_directory,
@@ -137,6 +142,7 @@ module AcpcTableManager
137
142
  config['table_manager_constants'],
138
143
  config['log_directory'],
139
144
  config['match_log_directory'],
145
+ config['proxy_pids_file'],
140
146
  interpolation_hash
141
147
  )
142
148
  @@exhibition_config = ExhibitionConfig.new(
@@ -145,7 +151,11 @@ module AcpcTableManager
145
151
  Logger.from_file_name(File.join(@@config.my_log_directory, 'exhibition_config.log'))
146
152
  )
147
153
 
148
- Mongoid.logger = Logger.from_file_name(File.join(@@config.log_directory, 'mongoid.log'))
154
+ # Moped.logger = Logger.from_file_name(File.join(@@config.log_directory, 'moped.log'))
155
+ # Mongoid.logger = Logger.from_file_name(File.join(@@config.log_directory, 'mongoid.log'))
156
+ # TODO: These should be set in configuration files
157
+ Moped.logger.level = ::Logger::FATAL
158
+ Mongoid.logger.level = ::Logger::FATAL
149
159
  Mongoid.load!(config['mongoid_config'], config['mongoid_env'].to_sym)
150
160
 
151
161
  if config['error_report']
@@ -156,6 +166,8 @@ module AcpcTableManager
156
166
  Rusen.settings.sections = config['error_report']['sections'] || [:backtrace]
157
167
  Rusen.settings.email_prefix = config['error_report']['email_prefix'] || '[ERROR] '
158
168
  Rusen.settings.smtp_settings = config['error_report']['smtp']
169
+
170
+ @@notifier = Rusen
159
171
  else
160
172
  @@config.log(__method__, {warning: "Email reporting disabled. Please set email configuration to enable this feature."}, Logger::Severity::WARN)
161
173
  end
@@ -182,7 +194,7 @@ module AcpcTableManager
182
194
  end
183
195
 
184
196
  def self.notify(exception)
185
- Rusen.notify exception
197
+ @@notifier.notify(exception) if @@notifier
186
198
  end
187
199
 
188
200
  def self.initialized?
@@ -1,3 +1,4 @@
1
+ require 'yaml'
1
2
  require_relative 'dealer'
2
3
  require_relative 'match'
3
4
 
@@ -8,36 +9,103 @@ module AcpcTableManager
8
9
  class Maintainer
9
10
  include SimpleLogging
10
11
 
12
+ def self.proxy_pids(pids_file)
13
+ if !File.exists?(pids_file)
14
+ File.open(pids_file, 'w') do |pids_file|
15
+ yield pids_file, {} if block_given?
16
+ end
17
+ else
18
+ File.open(pids_file, 'r+') do |pids_file|
19
+ pids = YAML.safe_load(pids_file) || {}
20
+ pids_file.seek(0, IO::SEEK_SET)
21
+ pids_file.truncate(0)
22
+ yield pids_file, pids if block_given?
23
+ end
24
+ end
25
+ end
26
+
27
+ def self.kill_orphan_proxies(pids, pids_file)
28
+ new_pids = []
29
+ pids.each do |pid_pair|
30
+ if AcpcDealer::process_exists?(pid_pair['proxy']) && !AcpcDealer::process_exists?(pid_pair['dealer'])
31
+ AcpcDealer::kill_process pid_pair['proxy']
32
+ sleep 1 # Give the process a chance to exit
33
+
34
+ if AcpcDealer::process_exists?(pid_pair['proxy'])
35
+ AcpcDealer::force_kill_process pid_pair['proxy']
36
+ sleep 1 # Give the process a chance to exit
37
+
38
+ if AcpcDealer::process_exists?(pid_pair['proxy'])
39
+ raise(
40
+ StandardError.new(
41
+ "Proxy process #{pid_pair['proxy']} couldn't be killed!"
42
+ )
43
+ )
44
+ end
45
+ end
46
+ else
47
+ new_pids << pid_pair
48
+ end
49
+ end
50
+ new_pids
51
+ end
52
+
53
+ def self.update_pids(pids)
54
+ pids, pids_file = proxy_pids proxy_pids_file do |pids_file, pids|
55
+ pids = kill_orphan_proxies pids, pids_file
56
+
57
+ matches_started = yield if block_given?
58
+
59
+ matches_started.each do |info|
60
+ if info
61
+ pids << {'dealer' => info[:dealer][:pid], 'proxy' => info[:proxy]}
62
+ end
63
+ end
64
+ pids_file.write(YAML.dump(pids)) unless pids.empty?
65
+ end
66
+ end
67
+
68
+ def self.proxy_pids_file() ::AcpcTableManager.config.proxy_pids_file end
69
+
11
70
  def initialize(logger_ = AcpcTableManager.new_log('table_manager.log'))
12
71
  @logger = logger_
13
-
14
72
  @table_queues = {}
15
- enqueue_waiting_matches
73
+
74
+ maintain!
16
75
 
17
76
  log(__method__)
18
77
  end
19
78
 
20
79
  def enqueue_waiting_matches(game_definition_key=nil)
80
+ queues_touched = []
21
81
  if game_definition_key
22
82
  @table_queues[game_definition_key] ||= ::AcpcTableManager::TableQueue.new(game_definition_key)
23
83
  matches_to_check = @table_queues[game_definition_key].my_matches.not_running.and.not_started.to_a
24
84
  matches_to_check.each do |m|
25
85
  unless @table_queues[game_definition_key].running_matches[m.id.to_s]
26
- @table_queues[game_definition_key].enqueue! m.id.to_s, m.dealer_options
86
+ queues_touched << @table_queues[game_definition_key].enqueue!(m.id.to_s, m.dealer_options)
27
87
  end
28
88
  end
29
89
  else
30
90
  ::AcpcTableManager.exhibition_config.games.keys.each do |game_definition_key|
31
- enqueue_waiting_matches game_definition_key
91
+ queues_touched += enqueue_waiting_matches(game_definition_key)
32
92
  end
33
93
  end
94
+ queues_touched
34
95
  end
35
96
 
36
97
  def maintain!
37
98
  log __method__, msg: "Starting maintenance"
38
99
 
39
- enqueue_waiting_matches
40
- @table_queues.each { |key, queue| queue.check_queue! }
100
+ self.class().update_pids self.class().proxy_pids_file do
101
+ queues_touched = enqueue_waiting_matches
102
+ matches_started = []
103
+ queues_touched.each do |_, queue|
104
+ matches_started << queue.check_queue!
105
+ end
106
+ matches_started
107
+ end
108
+
41
109
  clean_up_matches!
42
110
 
43
111
  log __method__, msg: "Finished maintenance"
@@ -61,7 +129,10 @@ module AcpcTableManager
61
129
  rescue Mongoid::Errors::DocumentNotFound
62
130
  return kill_match!(match_id)
63
131
  else
64
- @table_queues[m.game_definition_key.to_s].enqueue! match_id, options
132
+ self.class().update_pids self.class().proxy_pids_file do
133
+ @table_queues[m.game_definition_key.to_s].enqueue! match_id, options
134
+ @table_queues[m.game_definition_key.to_s].check_queue!
135
+ end
65
136
  end
66
137
  end
67
138
 
@@ -71,7 +142,9 @@ module AcpcTableManager
71
142
  rescue Mongoid::Errors::DocumentNotFound
72
143
  return kill_match!(match_id)
73
144
  else
74
- @table_queues[match.game_definition_key.to_s].start_proxy match
145
+ self.class().update_pids self.class().proxy_pids_file do
146
+ [@table_queues[match.game_definition_key.to_s].start_proxy(match)]
147
+ end
75
148
  end
76
149
  end
77
150
 
@@ -5,7 +5,7 @@ require 'fileutils'
5
5
  class Logger
6
6
  # Defaults correspond to Logger#new defaults
7
7
  def self.from_file_name(file_name, shift_age = 0, shift_size = 1048576)
8
- unless File.exists?(file_name)
8
+ unless File.exist?(file_name)
9
9
  FileUtils.mkdir_p File.dirname(file_name)
10
10
  FileUtils.touch file_name
11
11
  end
@@ -55,7 +55,6 @@ module AcpcTableManager
55
55
  log(__method__, msg: "Opponents started for #{match.id.to_s}")
56
56
 
57
57
  start_proxy match
58
- self
59
58
  end
60
59
 
61
60
  def start_proxy(match)
@@ -81,6 +80,7 @@ module AcpcTableManager
81
80
  pid: @running_matches[match.id.to_s][:proxy]
82
81
  }
83
82
  )
83
+ @running_matches[match.id.to_s]
84
84
  end
85
85
 
86
86
  def my_matches
@@ -114,7 +114,7 @@ module AcpcTableManager
114
114
  end
115
115
  end
116
116
 
117
- # @return (@see #dequeue!)
117
+ # @return +self+
118
118
  def enqueue!(match_id, dealer_options)
119
119
  log(
120
120
  __method__,
@@ -127,18 +127,18 @@ module AcpcTableManager
127
127
  )
128
128
 
129
129
  if @running_matches[match_id]
130
- return log(
130
+ log(
131
131
  __method__,
132
132
  msg: "Match #{match_id} already started!"
133
133
  )
134
+ return self
134
135
  end
135
136
 
136
137
  @matches_to_start << {match_id: match_id, options: dealer_options}
137
-
138
- check_queue!
138
+ self
139
139
  end
140
140
 
141
- # @return (@see #dequeue!)
141
+ # @return [Array] The list of PID information about the matches that were dequeued.
142
142
  def check_queue!
143
143
  log __method__
144
144
 
@@ -146,11 +146,14 @@ module AcpcTableManager
146
146
 
147
147
  log __method__, {num_running_matches: @running_matches.length, num_matches_to_start: @matches_to_start.length}
148
148
 
149
- if @running_matches.length < AcpcTableManager.exhibition_config.games[@game_definition_key]['max_num_matches']
150
- dequeue!
151
- else
152
- nil
149
+ matches_started = []
150
+ while !@matches_to_start.empty? && @running_matches.length < AcpcTableManager.exhibition_config.games[@game_definition_key]['max_num_matches']
151
+ matches_started << dequeue
153
152
  end
153
+
154
+ log __method__, {matches_started: matches_started, num_running_matches: @running_matches.length, num_matches_to_start: @matches_to_start.length}
155
+
156
+ matches_started
154
157
  end
155
158
 
156
159
  # @todo Shouldn't be necessary, so this method isn't called right now, but I've written it so I'll leave it for now
@@ -338,8 +341,8 @@ module AcpcTableManager
338
341
  end
339
342
 
340
343
  # @return [Object] The match that has been started or +nil+ if none could
341
- # be started.
342
- def dequeue!
344
+ # be started.
345
+ def dequeue
343
346
  log(
344
347
  __method__,
345
348
  num_matches_to_start: @matches_to_start.length
@@ -355,12 +358,12 @@ module AcpcTableManager
355
358
  begin
356
359
  match = Match.find match_id
357
360
  rescue Mongoid::Errors::DocumentNotFound
358
- return self if @matches_to_start.empty?
361
+ return nil if @matches_to_start.empty?
359
362
  else
360
363
  break
361
364
  end
362
365
  end
363
- return self unless match_id
366
+ return nil unless match_id
364
367
 
365
368
  options = match_info[:options]
366
369
 
@@ -452,6 +455,8 @@ module AcpcTableManager
452
455
  )
453
456
 
454
457
  start_players! match
458
+
459
+ @running_matches[match_id]
455
460
  end
456
461
  end
457
462
  end
@@ -1,3 +1,3 @@
1
1
  module AcpcTableManager
2
- VERSION = "1.0.9"
2
+ VERSION = "2.0.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acpc_table_manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.9
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dustin Morrill
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-12-11 00:00:00.000000000 Z
11
+ date: 2016-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pony
@@ -318,7 +318,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
318
318
  version: '0'
319
319
  requirements: []
320
320
  rubyforge_project:
321
- rubygems_version: 2.2.2
321
+ rubygems_version: 2.5.1
322
322
  signing_key:
323
323
  specification_version: 4
324
324
  summary: Backend components to the ACPC Poker GUI Client