qa_server 5.4.0 → 5.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ab89fc6147c1cf32de828a8b2cecaab3ca66b296
4
- data.tar.gz: 027160d4a1e0f0090a1c6d81cfdcd74fba5d1423
3
+ metadata.gz: cfe60b29f718a16c9c86b62e0bd7807c746147b1
4
+ data.tar.gz: 51dc3758debb4b924b7859ca82f9ed49eb3475a6
5
5
  SHA512:
6
- metadata.gz: aa48a9de27b5b612d590981dfbb9f4316f496a6ecee810bc25735f7ffd1d5fc73c4a6e9f63af65aaeb767a35d983a9c3680ab1cd27b5558ef7b4c11958d73efe
7
- data.tar.gz: 12c86bbeb3d41de071788f93fdfd3ef632a1300c77182a114124a5fd5895ac733e0c4f76b72e973a3cd7b5a691224b2fb7be21b2651e04a0a935ad283ca8a973
6
+ metadata.gz: 56e1811a7ee5b562a3e24d77fecba594955b5410824863a0745f895b2541d5d735e21c33b29b33047c4cb1d257489dc498d9bdb774f097a74c64954c2c7e0da8
7
+ data.tar.gz: '084ba6a28a84a2a235c2cb69f2aed5285399ba2e3718135302a5dbf3c297a225407a348cbf6b87ef1705b5cc59016b1bd3ae49a7b0947dda28c215961f9e0f9a'
@@ -22,3 +22,7 @@ Metrics/BlockLength:
22
22
  Exclude:
23
23
  - 'qa_server.gemspec'
24
24
  - 'spec/**/*.rb'
25
+
26
+ Metrics/ClassLength:
27
+ Exclude:
28
+ - 'lib/qa_server/configuration.rb'
@@ -1,3 +1,7 @@
1
+ ### 5.5.0 (2020-01-10)
2
+
3
+ * use caching with expiry for monitor status page
4
+
1
5
  ### 5.4.0 (2020-01-07)
2
6
 
3
7
  * adds config hour_offset_to_expire_cache
@@ -13,9 +13,7 @@ module QaServer
13
13
 
14
14
  # Sets up presenter with data to display in the UI
15
15
  def index
16
- refresh_tests
17
- historical_data = refresh_history
18
- performance_data = refresh_performance
16
+ latest_run
19
17
  @presenter = presenter_class.new(current_summary: latest_summary,
20
18
  current_failure_data: latest_failures,
21
19
  historical_summary_data: historical_data,
@@ -25,49 +23,39 @@ module QaServer
25
23
 
26
24
  private
27
25
 
26
+ # Sets @latest_run [QaServer::ScenarioRunRegistry]
28
27
  def latest_run
29
- @latest_run ||= scenario_run_registry_class.latest_run
28
+ Rails.cache.fetch("#{self.class}/#{__method__}", expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: refresh_tests?) do
29
+ Rails.logger.info("#{self.class}##{__method__} - Running Tests - cache expired or refresh requested (#{refresh_tests?})")
30
+ validate(authorities_list)
31
+ scenario_run_registry_class.save_run(scenarios_results: status_log.to_a)
32
+ scenario_run_registry_class.latest_run
33
+ end
30
34
  end
31
35
 
36
+ # Sets @latest_summary [QaServer::ScenarioRunSummary]
32
37
  def latest_summary
33
- @latest_summary ||= scenario_history_class.run_summary(scenario_run: latest_run)
38
+ scenario_history_class.run_summary(scenario_run: latest_run, force: refresh_tests?)
34
39
  end
35
40
 
36
41
  def latest_failures
37
- @status_data ||= scenario_history_class.run_failures(run_id: latest_run.id)
38
- end
39
-
40
- def update_summary_and_data
41
- scenario_run_registry_class.save_run(scenarios_results: status_log.to_a)
42
- @latest_summary = nil # reset so next request recalculates
43
- @latest_failures = nil # reset so next request recalculates
42
+ scenario_history_class.run_failures(run_id: latest_run.id, force: refresh_tests?)
44
43
  end
45
44
 
46
- def expired?
47
- @expired ||= latest_summary.blank? || latest_summary.run_dt_stamp < QaServer.monitoring_expires_at
48
- end
49
-
50
- def historical_summary_data(refresh: false)
51
- # TODO: Make this refresh the same way performance data refreshes.
52
- # Requires historical graph to move out of presenter so it can be created here only with refresh.
53
- if refresh
54
- @historical_summary_data = scenario_history_class.historical_summary
55
- # TODO: Need to recreate graph here. And need to only read the graph in presenter.
56
- end
57
- @historical_summary_data ||= scenario_history_class.historical_summary
45
+ # Sets @historical_data [Array<Hash>]
46
+ def historical_data
47
+ scenario_history_class.historical_summary(force: refresh_history?)
58
48
  end
59
49
 
60
- def performance_data(refresh: false)
61
- datatype = performance_datatype(refresh)
62
- return if datatype == :none
63
- @performance_data = nil if refresh
64
- @performance_data ||= performance_history_class.performance_data(datatype: datatype)
50
+ # Sets @performance_data [Hash<Hash>]
51
+ def performance_data
52
+ performance_history_class.performance_data(datatype: performance_datatype, force: refresh_performance?)
65
53
  end
66
54
 
67
- def performance_datatype(refresh) # rubocop:disable Metrics/CyclomaticComplexity
68
- return :all if display_performance_datatable? && display_performance_graph? && refresh
55
+ def performance_datatype
56
+ return :all if display_performance_datatable? && display_performance_graph?
69
57
  return :datatable if display_performance_datatable?
70
- return :graph if display_performance_graph? && refresh
58
+ return :graph if display_performance_graph?
71
59
  :none
72
60
  end
73
61
 
@@ -79,12 +67,6 @@ module QaServer
79
67
  @display_performance_graph ||= QaServer.config.display_performance_graph?
80
68
  end
81
69
 
82
- def refresh_tests
83
- return unless refresh_tests?
84
- validate(authorities_list)
85
- update_summary_and_data
86
- end
87
-
88
70
  def refresh_history
89
71
  historical_summary_data(refresh: refresh_history?)
90
72
  end
@@ -98,12 +80,13 @@ module QaServer
98
80
  end
99
81
 
100
82
  def refresh_all?
83
+ return false unless refresh?
101
84
  params[:refresh].nil? || params[:refresh].casecmp?('all') # nil is for backward compatibility
102
85
  end
103
86
 
104
87
  def refresh_tests?
105
- return false unless refresh? || expired?
106
- refresh_all? || params[:refresh].casecmp?('tests') || expired?
88
+ return false unless refresh?
89
+ refresh_all? || params[:refresh].casecmp?('tests')
107
90
  end
108
91
 
109
92
  def refresh_history?
@@ -112,8 +95,8 @@ module QaServer
112
95
  end
113
96
 
114
97
  def refresh_performance?
115
- return false unless refresh? || expired?
116
- refresh_all? || params[:refresh].casecmp?('performance') || expired?
98
+ return false unless refresh?
99
+ refresh_all? || params[:refresh].casecmp?('performance')
117
100
  end
118
101
  end
119
102
  end
@@ -41,6 +41,7 @@ module QaServer
41
41
  end
42
42
 
43
43
  def log(id:)
44
+ return if QaServer.config.suppress_logging_performance_datails
44
45
  Rails.logger.debug("*** performance data for id: #{id} ***")
45
46
  Rails.logger.debug(@cache[id].to_yaml)
46
47
  end
@@ -64,10 +64,10 @@ module QaServer
64
64
  # },
65
65
  # AGROVOC_LD4L_CACHE: { ... # same data for each authority }
66
66
  # }
67
- def performance_data(datatype: :datatable)
67
+ def performance_data(datatype: :datatable, force: false)
68
68
  return if datatype == :none
69
69
  QaServer.config.performance_cache.write_all
70
- data = calculate_data(datatype)
70
+ data = calculate_data(datatype, force: force)
71
71
  graphing_service_class.create_performance_graphs(performance_data: data) if calculate_graphdata? datatype
72
72
  data
73
73
  end
@@ -82,23 +82,23 @@ module QaServer
82
82
  datatype == :graph || datatype == :all
83
83
  end
84
84
 
85
- def calculate_data(datatype)
85
+ def calculate_data(datatype, force:)
86
86
  data = {}
87
87
  auths = authority_list_class.authorities_list
88
- data[ALL_AUTH] = data_for_authority(datatype: datatype)
89
- auths.each { |auth_name| data[auth_name] = data_for_authority(authority_name: auth_name, datatype: datatype) }
88
+ data[ALL_AUTH] = data_for_authority(datatype: datatype, force: force)
89
+ auths.each { |auth_name| data[auth_name] = data_for_authority(authority_name: auth_name, datatype: datatype, force: force) }
90
90
  data
91
91
  end
92
92
 
93
- def data_for_authority(authority_name: nil, datatype:)
93
+ def data_for_authority(authority_name: nil, datatype:, force:)
94
94
  action_data = {}
95
95
  [:search, :fetch, :all_actions].each do |action|
96
96
  data = {}
97
- data[FOR_DATATABLE] = data_table_stats(authority_name, action) if calculate_datatable?(datatype)
97
+ data[FOR_DATATABLE] = data_table_stats(authority_name, action, force: force) if calculate_datatable?(datatype)
98
98
  if calculate_graphdata?(datatype)
99
- data[FOR_DAY] = graph_data_service_class.average_last_24_hours(authority_name: authority_name, action: action)
100
- data[FOR_MONTH] = graph_data_service_class.average_last_30_days(authority_name: authority_name, action: action)
101
- data[FOR_YEAR] = graph_data_service_class.average_last_12_months(authority_name: authority_name, action: action)
99
+ data[FOR_DAY] = graph_data_service_class.average_last_24_hours(authority_name: authority_name, action: action, force: force)
100
+ data[FOR_MONTH] = graph_data_service_class.average_last_30_days(authority_name: authority_name, action: action, force: force)
101
+ data[FOR_YEAR] = graph_data_service_class.average_last_12_months(authority_name: authority_name, action: action, force: force)
102
102
  end
103
103
  action_data[action] = data
104
104
  end
@@ -106,18 +106,23 @@ module QaServer
106
106
  end
107
107
 
108
108
  # Get statistics for all available data.
109
- # @param [String] auth_name - limit statistics to records for the given authority (default: all authorities)
109
+ # @param auth_name [String] limit statistics to records for the given authority (default: all authorities)
110
+ # @param action [Symbol] one of :search, :fetch, :all_actions
111
+ # @param force [Boolean] if true, forces cache to regenerate; otherwise, returns value from cache unless expired
110
112
  # @returns [Hash] performance statistics for the datatable during the expected time period
111
113
  # @example
112
114
  # { retrieve_avg_ms: 12.3, graph_load_avg_ms: 2.1, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5,
113
115
  # retrieve_10th_ms: 12.3, graph_load_10th_ms: 12.3, normalization_10th_ms: 4.2, full_request_10th_ms: 16.5,
114
116
  # retrieve_90th_ms: 12.3, graph_load_90th_ms: 12.3, normalization_90th_ms: 4.2, full_request_90th_ms: 16.5 }
115
- def data_table_stats(auth_name, action)
116
- records = records_for_last_24_hours(auth_name) ||
117
- records_for_last_30_days(auth_name) ||
118
- records_for_last_12_months(auth_name) ||
119
- all_records(auth_name)
120
- stats_calculator_class.new(records, action: action).calculate_stats(avg: true, low: true, high: true)
117
+ def data_table_stats(auth_name, action, force:)
118
+ Rails.cache.fetch("#{self.class}/#{__method__}/#{auth_name || ALL_AUTH}/#{action}/#{FOR_DATATABLE}", expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: force) do
119
+ Rails.logger.info("#{self.class}##{__method__} - calculating performance datatable stats - cache expired or refresh requested (#{force})")
120
+ records = records_for_last_24_hours(auth_name) ||
121
+ records_for_last_30_days(auth_name) ||
122
+ records_for_last_12_months(auth_name) ||
123
+ all_records(auth_name)
124
+ stats_calculator_class.new(records, action: action).calculate_stats(avg: true, low: true, high: true)
125
+ end
121
126
  end
122
127
 
123
128
  def expected_time_period
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  # Provide access to the scenario_results_history database table which tracks specific scenario runs over time.
3
3
  module QaServer
4
- class ScenarioRunHistory < ActiveRecord::Base
4
+ class ScenarioRunHistory < ActiveRecord::Base # rubocop:disable Metrics/ClassLength
5
5
  self.table_name = 'scenario_run_history'
6
6
  belongs_to :scenario_run_registry
7
7
  enum scenario_type: [:connection, :accuracy, :performance], _suffix: :type
@@ -31,24 +31,28 @@ module QaServer
31
31
  end
32
32
 
33
33
  # Get a summary of passing/failing tests for a run.
34
- # @param scenario_run [ScenarioRunRegistry] the run on which to gather statistics
35
- # @returns [Hash] statistics on the requested run
36
- # @example
37
- # { run_id: 14,
38
- # failing_count: 3,
39
- # passing_count: 156,
40
- # total_count: 159,
41
- # authority_count: 22,
42
- # failing_authority_count: 1 }
43
- def self.run_summary(scenario_run:)
44
- return nil unless scenario_run&.id
45
- status = status_counts_in_run(run_id: scenario_run.id)
46
- summary_class.new(run_id: scenario_run.id,
47
- run_dt_stamp: scenario_run.dt_stamp,
48
- authority_count: authorities_in_run(run_id: scenario_run.id).count,
49
- failing_authority_count: authorities_with_failures_in_run(run_id: scenario_run.id).count,
50
- passing_scenario_count: status['good'],
51
- failing_scenario_count: status['bad'] + status['unknown'])
34
+ # @param scenario_run [QaServer::ScenarioRunRegistry] the run on which to gather statistics
35
+ # @param force [Boolean] if true, forces cache to regenerate; otherwise, returns value from cache unless expired
36
+ # @returns [QaServer::ScenarioRunSummary] statistics on the requested run
37
+ # @example ScenarioRunSummary includes methods for accessing
38
+ # * run_id: 14,
39
+ # * run_dt_stamp:
40
+ # * authority_count: 22,
41
+ # * failing_authority_count: 1
42
+ # * passing_scenario_count: 156,
43
+ # * failing_scenario_count: 3,
44
+ # * total_scenario_count: 159,
45
+ def self.run_summary(scenario_run:, force: false)
46
+ Rails.cache.fetch("#{self.class}/#{__method__}", expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: force) do
47
+ Rails.logger.info("#{self.class}##{__method__} - creating summary of latest run - cache expired or refresh requested (#{force})")
48
+ status = status_counts_in_run(run_id: scenario_run.id)
49
+ summary_class.new(run_id: scenario_run.id,
50
+ run_dt_stamp: scenario_run.dt_stamp,
51
+ authority_count: authorities_in_run(run_id: scenario_run.id).count,
52
+ failing_authority_count: authorities_with_failures_in_run(run_id: scenario_run.id).count,
53
+ passing_scenario_count: status['good'],
54
+ failing_scenario_count: status['bad'] + status['unknown'])
55
+ end
52
56
  end
53
57
 
54
58
  # Get set of all scenario results for a run.
@@ -85,6 +89,7 @@ module QaServer
85
89
  # err_message: "Not enough search results returned",
86
90
  # scenario_type: :connection
87
91
  # run_time: 0.123 } ]
92
+ # @deprecated Not used anywhere. Being removed.
88
93
  def self.run_results(run_id:, authority_name: nil, status: nil, url: nil)
89
94
  return [] unless run_id
90
95
  where = {}
@@ -94,9 +99,11 @@ module QaServer
94
99
  where[:url] = url if url.present?
95
100
  QaServer::ScenarioRunHistory.where(where).to_a
96
101
  end
102
+ deprecation_deprecate run_results: "Not used anywhere. Being removed."
97
103
 
98
104
  # Get set of failures for a run, if any.
99
105
  # @param run_id [Integer] the run on which to gather statistics
106
+ # @param force [Boolean] if true, forces cache to regenerate; otherwise, returns value from cache unless expired
100
107
  # @returns [Array<Hash>] scenario details for any failing scenarios in the run
101
108
  # @example
102
109
  # [ { status: :bad,
@@ -117,32 +124,43 @@ module QaServer
117
124
  # err_message: "Not enough search results returned",
118
125
  # scenario_type: :connection
119
126
  # run_time: 0.123 } ]
120
- def self.run_failures(run_id:)
127
+ def self.run_failures(run_id:, force: false)
121
128
  return [] unless run_id
122
- QaServer::ScenarioRunHistory.where(scenario_run_registry_id: run_id).where.not(status: :good).to_a
129
+ Rails.cache.fetch("#{self.class}/#{__method__}", expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: force) do
130
+ Rails.logger.info("#{self.class}##{__method__} - finding failures in latest run - cache expired or refresh requested (#{force})")
131
+ QaServer::ScenarioRunHistory.where(scenario_run_registry_id: run_id).where.not(status: :good).to_a
132
+ end
123
133
  end
124
134
 
125
135
  # Get a summary level of historical data
126
- # @returns [Array<Hash>] scenario details for any failing scenarios in the run (auth_name, failing, passing)
127
- # @example
136
+ # @returns [Array<Array>] summary of passing/failing tests for each authority
137
+ # @example [auth_name, failing, passing]
128
138
  # [ [ 'agrovoc', 0, 24 ],
129
139
  # [ 'geonames_ld4l_cache', 2, 22 ] ... ]
130
- def self.historical_summary
131
- runs = all_runs_per_authority
132
- failures = failing_runs_per_authority
133
- return [] unless runs.present?
134
- data = []
135
- runs.each do |auth_name, run_count|
136
- auth_data = []
137
- auth_data[0] = auth_name
138
- failure_count = (failures.key? auth_name) ? failures[auth_name] : 0 # rubocop:disable Style/TernaryParentheses
139
- auth_data[1] = failure_count
140
- auth_data[2] = run_count - failure_count # passing
141
- data << auth_data
140
+ def self.historical_summary(force: false)
141
+ Rails.cache.fetch("#{self.class}/#{__method__}", expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: force) do
142
+ Rails.logger.info("#{self.class}##{__method__} - calculating pass/fail per authority across all time - cache expired or refresh requested (#{force})")
143
+ runs = all_runs_per_authority
144
+ failures = failing_runs_per_authority
145
+ return [] unless runs.present?
146
+ data = []
147
+ runs.each do |auth_name, run_count|
148
+ data << pass_fail_stats_for_authority(failures, auth_name, run_count)
149
+ end
150
+ data
142
151
  end
143
- data
144
152
  end
145
153
 
154
+ def self.pass_fail_stats_for_authority(failures, auth_name, run_count)
155
+ auth_data = []
156
+ auth_data[0] = auth_name
157
+ failure_count = failures.key?(auth_name) ? failures[auth_name] : 0
158
+ auth_data[1] = failure_count
159
+ auth_data[2] = run_count - failure_count # passing
160
+ auth_data
161
+ end
162
+ private_class_method :pass_fail_stats_for_authority
163
+
146
164
  def self.authorities_in_run(run_id:)
147
165
  QaServer::ScenarioRunHistory.where(scenario_run_registry_id: run_id).pluck(:authority_name).uniq
148
166
  end
@@ -153,6 +171,8 @@ module QaServer
153
171
  end
154
172
  private_class_method :authorities_with_failures_in_run
155
173
 
174
+ # @return [Hash] status counts across all authorities (used for current test summary)
175
+ # @example { "good" => 23, "bad" => 3, "unknown" => 0 }
156
176
  def self.status_counts_in_run(run_id:)
157
177
  status = QaServer::ScenarioRunHistory.group('status').where(scenario_run_registry_id: run_id).count
158
178
  status["good"] = 0 unless status.key? "good"
@@ -5,7 +5,7 @@ module QaServer
5
5
  self.table_name = 'scenario_run_registry'
6
6
  has_many :scenario_run_history, foreign_key: :scenario_run_registry_id
7
7
 
8
- # Get the latest saved run of scenarios.
8
+ # @return [ScenarioRunRegistry] registry data for latest run (e.g. id, dt_stamp)
9
9
  def self.latest_run
10
10
  return nil unless QaServer::ScenarioRunRegistry.last
11
11
  QaServer::ScenarioRunRegistry.last # Can we count on last to always be the one with the latest dt_stamp?
@@ -14,21 +14,27 @@ module QaServer
14
14
  # latest_run.id
15
15
  end
16
16
 
17
- # Get the latest saved status.
17
+ # @return [Integer] id for latest test run
18
+ # @deprecated Not used anywhere. Being removed.
18
19
  def self.latest_run_id
19
20
  latest = latest_run
20
21
  return nil unless latest
21
22
  lastest.id
22
23
  end
24
+ deprecation_deprecate latest_run_id: "Not used anywhere. Being removed."
23
25
 
24
- def self.save_run(scenarios_results:)
25
- run = QaServer::ScenarioRunRegistry.create(dt_stamp: dt_stamp_now_et)
26
- scenarios_results.each { |result| QaServer::ScenarioRunHistory.save_result(run_id: run.id, scenario_result: result) }
26
+ # @return [String] datetime stamp of first registered run
27
+ def self.first_run_dt
28
+ Rails.cache.fetch("#{self.class}/#{__method__}", expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour) do
29
+ QaServer::ScenarioRunRegistry.first.dt_stamp.in_time_zone("Eastern Time (US & Canada)").strftime("%m/%d/%y - %I:%M %p")
30
+ end
27
31
  end
28
32
 
29
- def self.dt_stamp_now_et
30
- Time.now.in_time_zone("Eastern Time (US & Canada)")
33
+ # Register and save latest test run results
34
+ # @param scenarios_results [Array<Hash>] results of latest test run
35
+ def self.save_run(scenarios_results:)
36
+ run = QaServer::ScenarioRunRegistry.create(dt_stamp: QaServer.current_time)
37
+ scenarios_results.each { |result| QaServer::ScenarioRunHistory.save_result(run_id: run.id, scenario_result: result) }
31
38
  end
32
- private_class_method :dt_stamp_now_et
33
39
  end
34
40
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- # Abstract class that parses the authority configuration from the yml file into the parts needed by inheriting scenario types.
2
+ # Holds test run summary data providing methods for accessing each data point.
3
3
  module QaServer
4
4
  class ScenarioRunSummary
5
5
  # @return [Integer] the id of the scenario run being summarized
@@ -17,15 +17,15 @@ module PrependedRdf::RdfGraph
17
17
  raise TypeError, "#{self} is immutable" if immutable?
18
18
  phid, real_url = parse_phid(url)
19
19
  performance_udpates = {}
20
- start_time_s = Time.now.to_f
20
+ start_time_s = QaServer.current_time_s
21
21
 
22
22
  reader = RDF::Reader.open(real_url, { base_uri: real_url }.merge(options))
23
23
 
24
- end_time_s = Time.now.to_f
24
+ end_time_s = QaServer.current_time_s
25
25
  performance_udpates[:retrieve_time_ms] = (end_time_s - start_time_s) * 1000
26
26
  QaServer.config.performance_tracker.write "#{format('%.6f', end_time_s - start_time_s)}, " # read data
27
27
 
28
- start_time_s = Time.now.to_f
28
+ start_time_s = QaServer.current_time_s
29
29
 
30
30
  if graph_name
31
31
  statements = []
@@ -40,7 +40,7 @@ module PrependedRdf::RdfGraph
40
40
  nil
41
41
  end
42
42
 
43
- end_time_s = Time.now.to_f
43
+ end_time_s = QaServer.current_time_s
44
44
  performance_udpates[:graph_load_time_ms] = (end_time_s - start_time_s) * 1000
45
45
  QaServer.config.performance_cache.update(id: phid, updates: performance_udpates)
46
46
  QaServer.config.performance_tracker.write "#{format('%.6f', end_time_s - start_time_s)}, " # load graph
@@ -16,7 +16,7 @@ module QaServer::MonitorStatus
16
16
 
17
17
  # @return [String] date of first recorded test run
18
18
  def first_updated
19
- QaServer::ScenarioRunRegistry.first.dt_stamp.in_time_zone("Eastern Time (US & Canada)").strftime("%m/%d/%y - %I:%M %p")
19
+ QaServer::ScenarioRunRegistry.first_run_dt
20
20
  end
21
21
 
22
22
  # @return [Integer] number of loaded authorities
@@ -10,6 +10,9 @@ module QaServer
10
10
  self.performance_data_class = QaServer::PerformanceHistory
11
11
 
12
12
  # Get hourly average for the past 24 hours.
13
+ # @param authority_name [String] limit statistics to records for the given authority (default: all authorities)
14
+ # @param action [Symbol] one of :search, :fetch, :all_actions
15
+ # @param force [Boolean] if true, forces cache to regenerate; otherwise, returns value from cache unless expired
13
16
  # @returns [Hash] performance statistics for the past 24 hours
14
17
  # @example
15
18
  # { 0: { hour: '1400', stats: { load_avg_ms: 12.3, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }},
@@ -18,22 +21,19 @@ module QaServer
18
21
  # ...,
19
22
  # 23: { hour: 'NOW', stats: { load_avg_ms: 12.3, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }}
20
23
  # }
21
- def average_last_24_hours(authority_name: nil, action: nil)
22
- start_hour = Time.now.getlocal.beginning_of_hour - 23.hours
23
- avgs = {}
24
- 0.upto(23).each do |idx|
25
- records = records_by(authority_name, action, start_hour..start_hour.end_of_hour)
26
- stats = stats_calculator_class.new(records).calculate_stats(avg: true, full: false)
27
- data = {}
28
- data[BY_HOUR] = performance_by_hour_label(idx, start_hour)
29
- data[STATS] = stats
30
- avgs[idx] = data
31
- start_hour += 1.hour
24
+ def average_last_24_hours(authority_name: nil, action: nil, force: false)
25
+ Rails.cache.fetch("#{self.class}/#{__method__}/#{authority_name || ALL_AUTH}/#{action}/#{FOR_DAY}",
26
+ expires_in: QaServer.current_time.end_of_hour - QaServer.current_time,
27
+ race_condition_ttl: 1.hour, force: force) do
28
+ Rails.logger.info("#{self.class}##{__method__} - calculating performance stats for last 24 hours - cache expired or refresh requested (#{force})")
29
+ calculate_last_24_hours(authority_name, action)
32
30
  end
33
- avgs
34
31
  end
35
32
 
36
33
  # Get daily average for the past 30 days.
34
+ # @param authority_name [String] limit statistics to records for the given authority (default: all authorities)
35
+ # @param action [Symbol] one of :search, :fetch, :all_actions
36
+ # @param force [Boolean] if true, forces cache to regenerate; otherwise, returns value from cache unless expired
37
37
  # @returns [Hash] performance statistics for the past 30 days
38
38
  # @example
39
39
  # { 0: { day: '07-15-2019', stats: { load_avg_ms: 12.3, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }},
@@ -42,22 +42,18 @@ module QaServer
42
42
  # ...,
43
43
  # 29: { day: 'TODAY', stats: { load_avg_ms: 12.3, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }}
44
44
  # }
45
- def average_last_30_days(authority_name: nil, action: nil)
46
- start_day = Time.now.getlocal.beginning_of_day - 29.days
47
- avgs = {}
48
- 0.upto(29).each do |idx|
49
- records = records_by(authority_name, action, start_day..start_day.end_of_day)
50
- stats = stats_calculator_class.new(records).calculate_stats(avg: true, full: false)
51
- data = {}
52
- data[BY_DAY] = performance_by_day_label(idx, start_day)
53
- data[STATS] = stats
54
- avgs[idx] = data
55
- start_day += 1.day
45
+ def average_last_30_days(authority_name: nil, action: nil, force: false)
46
+ Rails.cache.fetch("#{self.class}/#{__method__}/#{authority_name || ALL_AUTH}/#{action}/#{FOR_MONTH}",
47
+ expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: force) do
48
+ Rails.logger.info("#{self.class}##{__method__} - calculating performance stats for last 30 days - cache expired or refresh requested (#{force})")
49
+ calculate_last_30_days(authority_name, action)
56
50
  end
57
- avgs
58
51
  end
59
52
 
60
53
  # Get daily average for the past 12 months.
54
+ # @param authority_name [String] limit statistics to records for the given authority (default: all authorities)
55
+ # @param action [Symbol] one of :search, :fetch, :all_actions
56
+ # @param force [Boolean] if true, forces cache to regenerate; otherwise, returns value from cache unless expired
61
57
  # @returns [Hash] performance statistics for the past 12 months
62
58
  # @example
63
59
  # { 0: { month: '09-2019', stats: { load_avg_ms: 12.3, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }},
@@ -66,19 +62,12 @@ module QaServer
66
62
  # ...,
67
63
  # 11: { month: '08-2019', stats: { load_avg_ms: 12.3, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }}
68
64
  # }
69
- def average_last_12_months(authority_name: nil, action: nil)
70
- start_month = Time.now.getlocal.beginning_of_month - 11.months
71
- avgs = {}
72
- 0.upto(11).each do |idx|
73
- records = records_by(authority_name, action, start_month..start_month.end_of_month)
74
- stats = stats_calculator_class.new(records).calculate_stats(avg: true, full: false)
75
- data = {}
76
- data[BY_MONTH] = start_month.strftime("%m-%Y")
77
- data[STATS] = stats
78
- avgs[idx] = data
79
- start_month += 1.month
65
+ def average_last_12_months(authority_name: nil, action: nil, force: false)
66
+ Rails.cache.fetch("#{self.class}/#{__method__}/#{authority_name || ALL_AUTH}/#{action}/#{FOR_YEAR}",
67
+ expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: force) do
68
+ Rails.logger.info("#{self.class}##{__method__} - calculating performance stats for last 12 months - cache expired or refresh requested (#{force})")
69
+ calculate_last_12_months(authority_name, action)
80
70
  end
81
- avgs
82
71
  end
83
72
 
84
73
  private
@@ -109,6 +98,51 @@ module QaServer
109
98
  ""
110
99
  end
111
100
  end
101
+
102
+ def calculate_last_24_hours(authority_name, action)
103
+ start_hour = QaServer.current_time.beginning_of_hour - 23.hours
104
+ avgs = {}
105
+ 0.upto(23).each do |idx|
106
+ records = records_by(authority_name, action, start_hour..start_hour.end_of_hour)
107
+ stats = stats_calculator_class.new(records).calculate_stats(avg: true, full: false)
108
+ data = {}
109
+ data[BY_HOUR] = performance_by_hour_label(idx, start_hour)
110
+ data[STATS] = stats
111
+ avgs[idx] = data
112
+ start_hour += 1.hour
113
+ end
114
+ avgs
115
+ end
116
+
117
+ def calculate_last_30_days(authority_name, action)
118
+ start_day = QaServer.current_time.beginning_of_day - 29.days
119
+ avgs = {}
120
+ 0.upto(29).each do |idx|
121
+ records = records_by(authority_name, action, start_day..start_day.end_of_day)
122
+ stats = stats_calculator_class.new(records).calculate_stats(avg: true, full: false)
123
+ data = {}
124
+ data[BY_DAY] = performance_by_day_label(idx, start_day)
125
+ data[STATS] = stats
126
+ avgs[idx] = data
127
+ start_day += 1.day
128
+ end
129
+ avgs
130
+ end
131
+
132
+ def calculate_last_12_months(authority_name, action)
133
+ start_month = QaServer.current_time.beginning_of_month - 11.months
134
+ avgs = {}
135
+ 0.upto(11).each do |idx|
136
+ records = records_by(authority_name, action, start_month..start_month.end_of_month)
137
+ stats = stats_calculator_class.new(records).calculate_stats(avg: true, full: false)
138
+ data = {}
139
+ data[BY_MONTH] = start_month.strftime("%m-%Y")
140
+ data[STATS] = stats
141
+ avgs[idx] = data
142
+ start_month += 1.month
143
+ end
144
+ avgs
145
+ end
112
146
  end
113
147
  end
114
148
  end
@@ -73,4 +73,9 @@ QaServer.config do |config|
73
73
  # impact and may need to be suppressed. Performance stats will not be gathered when this config is true.
74
74
  # @param [Boolean] do not gather performance data when true (defaults to false for backward compatibitily)
75
75
  # config.suppress_performance_gathering = false
76
+
77
+ # Performance data is gathered on every incoming query. Basic stats are logged from QA. Full stats are logged
78
+ # by QaServer and can eat up logging realestate. To suppress the logging of details, set this config to true.
79
+ # @param [Boolean] do not log performance data details when true (defaults to false for backward compatibitily)
80
+ # config.suppress_logging_performance_datails = false
76
81
  end
@@ -179,6 +179,15 @@ module QaServer
179
179
  @suppress_performance_gathering ||= false
180
180
  end
181
181
 
182
+ # Performance data is gathered on every incoming query. Basic stats are logged from QA. Full stats are logged
183
+ # by QaServer and can eat up logging realestate. To suppress the logging of details, set this config to true.
184
+ # @param [Boolean] do not log performance data details when true (defaults to false for backward compatibitily)
185
+ attr_writer :suppress_logging_performance_datails
186
+ def suppress_logging_performance_datails
187
+ @suppress_logging_performance_datails ||= false
188
+ end
189
+
190
+ # TODO: consider refactor performance caching to use Rails cache
182
191
  def performance_cache
183
192
  @performance_cache ||= QaServer::PerformanceCache.new
184
193
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module QaServer
3
- VERSION = '5.4.0'
3
+ VERSION = '5.5.0'
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qa_server
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.4.0
4
+ version: 5.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - E. Lynette Rayle
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-07 00:00:00.000000000 Z
11
+ date: 2020-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails