qa_server 5.5.1 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +53 -0
- data/app/controllers/{qa_server/authority_validation_controller.rb → concerns/qa_server/authority_validation_behavior.rb} +13 -11
- data/app/controllers/qa_server/authority_list_controller.rb +5 -1
- data/app/controllers/qa_server/check_status_controller.rb +5 -1
- data/app/controllers/qa_server/monitor_status_controller.rb +40 -28
- data/app/jobs/qa_server/monitor_tests_job.rb +50 -0
- data/app/models/qa_server/performance_cache.rb +11 -3
- data/app/models/qa_server/performance_history.rb +24 -106
- data/app/models/qa_server/scenario_run_history.rb +161 -176
- data/app/models/qa_server/scenario_run_registry.rb +4 -4
- data/app/prepends/prepended_linked_data/find_term.rb +4 -4
- data/app/prepends/prepended_linked_data/search_query.rb +4 -4
- data/app/prepends/prepended_rdf/rdf_graph.rb +4 -4
- data/app/presenters/concerns/qa_server/monitor_status/performance_datatable_behavior.rb +23 -1
- data/app/presenters/qa_server/check_status_presenter.rb +4 -4
- data/app/presenters/qa_server/monitor_status/current_status_presenter.rb +17 -5
- data/app/presenters/qa_server/monitor_status/history_presenter.rb +40 -19
- data/app/presenters/qa_server/monitor_status/performance_presenter.rb +3 -1
- data/app/presenters/qa_server/monitor_status_presenter.rb +9 -9
- data/app/services/qa_server/monitor_cache_service.rb +22 -0
- data/app/services/qa_server/performance_calculator_service.rb +18 -7
- data/app/services/qa_server/performance_datatable_service.rb +82 -0
- data/app/services/qa_server/performance_graph_data_service.rb +140 -82
- data/app/services/qa_server/performance_graphing_service.rb +15 -12
- data/app/services/qa_server/time_period_service.rb +93 -0
- data/app/services/qa_server/time_service.rb +29 -0
- data/app/validators/qa_server/scenario_validator.rb +3 -3
- data/app/validators/qa_server/search_scenario_validator.rb +3 -3
- data/app/views/qa_server/monitor_status/_performance.html.erb +2 -1
- data/app/views/qa_server/monitor_status/_test_history.html.erb +1 -2
- data/app/views/qa_server/monitor_status/_test_summary.html.erb +2 -2
- data/config/locales/qa_server.en.yml +3 -4
- data/lib/generators/qa_server/templates/config/initializers/qa_server.rb +4 -0
- data/lib/qa_server.rb +0 -23
- data/lib/qa_server/configuration.rb +20 -0
- data/lib/qa_server/version.rb +1 -1
- data/spec/lib/qa_server_spec.rb +0 -51
- data/spec/services/qa_server/monitor_cache_service_spec.rb +20 -0
- data/spec/services/qa_server/time_period_service_spec.rb +246 -0
- data/spec/services/qa_server/time_service_spec.rb +50 -0
- metadata +14 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 860edda3341250dd5f1fc4db164b95f8f24bf832
|
4
|
+
data.tar.gz: 89cb1ccc0f86ef647d490dd416bf27b00f598d86
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f43f63cbfda11c203e79fb8aeeb4a8f05dac3051ea4225593fe82244343d35b8076a3db11672c913bf80eb8df8cfd0216bc7a6218d296c9772b516e32edeb41f
|
7
|
+
data.tar.gz: 9192ba67322874947fc9f979d7545369de86d041a533361621ac091013cbb04230b0f756d2b6d570a0c5fc992dce27548d6b86dfd93ff95733c39a134b542546
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
### 6.0.0 (2020-02-13)
|
2
|
+
|
3
|
+
* refactor generation of performance graphs to minimize db access and calculations
|
4
|
+
* shorten race_condition times for caching
|
5
|
+
* rename jobs_logger to be monitor_logger
|
6
|
+
* run monitoring tests in background
|
7
|
+
* move methods from QaServer to services
|
8
|
+
* use presenter to get failure data
|
9
|
+
* move controller validation code to module include
|
10
|
+
* limit historical data to configurable time period
|
11
|
+
* move time_period where clause construction to service
|
12
|
+
|
1
13
|
### 5.5.1 (2020-01-29)
|
2
14
|
|
3
15
|
* fix - check for nil before calling .each
|
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# QaServer
|
2
|
+
|
2
3
|
This rails engine can be installed into your app to serve as a Questioning Authority (QA) Server for accessing external authorities. It is part of a larger architecture supporting linked data authority access. From this engine, you can send a search query and get back multiple results OR you can fetch a single term. The engine provides UI for monitoring connections to configured authorities and the ability to check the current status of a single authority to determine if it is up and running now.
|
3
4
|
|
4
5
|
## Reference
|
@@ -25,6 +26,7 @@ Only required if you want to generate status charts. Generated charts will be s
|
|
25
26
|
`app/assets/images/qa_server/charts` directory. By default status is displayed in a table.
|
26
27
|
|
27
28
|
1. [ImageMagick](http://www.imagemagick.org/)
|
29
|
+
2. job queue processor of your choice
|
28
30
|
|
29
31
|
### Installation Instructions
|
30
32
|
|
@@ -58,6 +60,57 @@ $ rake db:migrate
|
|
58
60
|
|
59
61
|
If upgrading instead of installing, see the Release notes for steps you may need to take manually since you won't be running the installer.
|
60
62
|
|
63
|
+
#### Setting up monitoring
|
64
|
+
|
65
|
+
Monitoring runs once a day as a background job.
|
66
|
+
|
67
|
+
##### Configuring cache expiration
|
68
|
+
|
69
|
+
There are several configurations that control when the monitoring job will execute.
|
70
|
+
|
71
|
+
```
|
72
|
+
# Preferred time zone for reporting historical data and performance data
|
73
|
+
# @param [String] time zone name
|
74
|
+
# @see https://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html for possible values of TimeZone names
|
75
|
+
attr_writer :preferred_time_zone_name
|
76
|
+
def preferred_time_zone_name
|
77
|
+
@preferred_time_zone_name ||= 'Eastern Time (US & Canada)'
|
78
|
+
end
|
79
|
+
|
80
|
+
# Set preferred hour to expire caches related to slow running calculations (e.g. monitoring tests, performance data)
|
81
|
+
# @param [Integer] count of hours after midnight (0-23 with 0=midnight)
|
82
|
+
# @raise [ArgumentError] if offset is not between 0 and 23
|
83
|
+
# @example
|
84
|
+
# For preferred_time_zone_name of 'Eastern Time (US & Canada)', use 3 for slow down at midnight PT/3am ET
|
85
|
+
# For preferred_time_zone_name of 'Pacific Time (US & Canada)', use 0 for slow down at midnight PT/3am ET
|
86
|
+
def hour_offset_to_expire_cache=(offset)
|
87
|
+
raise ArgumentError, 'offset must be between 0 and 23' unless (0..23).cover? offset
|
88
|
+
@hour_offset_to_expire_cache = offset
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
With the default values set for the cache configurations, the cache will expire at midnight Pacific Time/3am Eastern Time.
|
93
|
+
|
94
|
+
##### Process for updating monitoring tests
|
95
|
+
|
96
|
+
Monitoring works in conjuction with the cache. When the cache expires, the monitoring tests will run the next time the monitor status page is accessed. When the monitor status page loads, it attempts to get the data for the page from the cache. If the cache has expired, it will get the previous day's data and kick off a background job to run the tests and update the cache.
|
97
|
+
|
98
|
+
##### Controlling when tests run
|
99
|
+
|
100
|
+
Because this process is launched by access to the monitor status page, it will not by default run the monitoring tests everyday. In our system, we set up Pingdom to access the monitor status page hourly around the clock. If an error occurs during the latest testing, the monitor status page includes a CSS class `summary-status-bad` and displays error results. Pingdom is configured to send a notification if the `summary-status-bad` CSS class is on the page, letting us know that we need to look into a problem with authority access.
|
101
|
+
|
102
|
+
##### Setting up background jobs
|
103
|
+
|
104
|
+
Reference: https://guides.rubyonrails.org/active_job_basics.html
|
105
|
+
|
106
|
+
Since this job is not critical for end users, you can set up jobs to be processed by the ruby provided in-memory job queue. The risk here is that if the server restarts or some other failure occurs, jobs in that queue are lost. If this is unacceptable for your system, then you will want to setup a 3rd party job queue ([more info...](https://guides.rubyonrails.org/active_job_basics.html#starting-the-backend)).
|
107
|
+
|
108
|
+
To configure in-memory job queue, add the following to config/environments/production.rb
|
109
|
+
|
110
|
+
```
|
111
|
+
config.active_job.queue_adapter = :async # runs in-memory; a crash will lose the job
|
112
|
+
```
|
113
|
+
|
61
114
|
#### Test the install
|
62
115
|
|
63
116
|
* Start rails server with `rails s`
|
@@ -1,21 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module QaServer
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
class_attribute :validator_class,
|
7
|
-
:lister_class,
|
8
|
-
:logger_class
|
9
|
-
|
10
|
-
self.validator_class = QaServer::AuthorityValidatorService
|
11
|
-
self.lister_class = QaServer::AuthorityListerService
|
12
|
-
self.logger_class = QaServer::ScenarioLogger
|
3
|
+
module AuthorityValidationBehavior
|
4
|
+
extend ActiveSupport::Concern
|
13
5
|
|
14
6
|
VALIDATION_TYPE_PARAM = :validation_type
|
15
7
|
VALIDATE_CONNECTIONS = 'connections'
|
16
8
|
VALIDATE_ACCURACY = 'accuracy'
|
17
9
|
ALL_VALIDATIONS = 'all_checks'
|
18
|
-
DEFAULT_VALIDATION_TYPE =
|
10
|
+
DEFAULT_VALIDATION_TYPE = QaServer::AuthorityValidatorService
|
11
|
+
|
12
|
+
included do
|
13
|
+
class_attribute :validator_class,
|
14
|
+
:lister_class,
|
15
|
+
:logger_class
|
16
|
+
|
17
|
+
self.validator_class = QaServer::AuthorityValidatorService
|
18
|
+
self.lister_class = QaServer::AuthorityListerService
|
19
|
+
self.logger_class = QaServer::ScenarioLogger
|
20
|
+
end
|
19
21
|
|
20
22
|
private
|
21
23
|
|
@@ -1,7 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
# Controller for Authorities header menu item
|
3
3
|
module QaServer
|
4
|
-
class AuthorityListController <
|
4
|
+
class AuthorityListController < ApplicationController
|
5
|
+
layout 'qa_server'
|
6
|
+
|
7
|
+
include QaServer::AuthorityValidationBehavior
|
8
|
+
|
5
9
|
class_attribute :presenter_class
|
6
10
|
self.presenter_class = QaServer::AuthorityListPresenter
|
7
11
|
|
@@ -1,7 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
# Controller for Check Status header menu item
|
3
3
|
module QaServer
|
4
|
-
class CheckStatusController <
|
4
|
+
class CheckStatusController < ApplicationController
|
5
|
+
layout 'qa_server'
|
6
|
+
|
7
|
+
include QaServer::AuthorityValidationBehavior
|
8
|
+
|
5
9
|
ALL_AUTHORITIES = '__all__'
|
6
10
|
|
7
11
|
class_attribute :presenter_class
|
@@ -1,45 +1,58 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
# Controller for Monitor Status header menu item
|
3
3
|
module QaServer
|
4
|
-
class MonitorStatusController <
|
4
|
+
class MonitorStatusController < ApplicationController
|
5
|
+
layout 'qa_server'
|
6
|
+
|
7
|
+
include QaServer::AuthorityValidationBehavior
|
8
|
+
|
5
9
|
class_attribute :presenter_class,
|
6
10
|
:scenario_run_registry_class,
|
7
11
|
:scenario_history_class,
|
8
|
-
:performance_history_class
|
12
|
+
:performance_history_class,
|
13
|
+
:graphing_service_class
|
9
14
|
self.presenter_class = QaServer::MonitorStatusPresenter
|
10
15
|
self.scenario_run_registry_class = QaServer::ScenarioRunRegistry
|
11
16
|
self.scenario_history_class = QaServer::ScenarioRunHistory
|
12
17
|
self.performance_history_class = QaServer::PerformanceHistory
|
18
|
+
self.graphing_service_class = QaServer::PerformanceGraphingService
|
13
19
|
|
14
20
|
# Sets up presenter with data to display in the UI
|
15
21
|
def index
|
16
|
-
|
22
|
+
log_header
|
23
|
+
latest_test_run
|
17
24
|
@presenter = presenter_class.new(current_summary: latest_summary,
|
18
25
|
current_failure_data: latest_failures,
|
19
26
|
historical_summary_data: historical_data,
|
20
|
-
performance_data:
|
27
|
+
performance_data: performance_table_data)
|
28
|
+
update_performance_graphs
|
21
29
|
render 'index', status: :internal_server_error if latest_summary.failing_authority_count.positive?
|
22
30
|
end
|
23
31
|
|
24
32
|
private
|
25
33
|
|
26
|
-
# Sets @
|
27
|
-
def
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
34
|
+
# Sets @latest_test_run [QaServer::ScenarioRunRegistry]
|
35
|
+
def latest_test_run
|
36
|
+
@latest_test_run ||= latest_test_run_from_cache
|
37
|
+
end
|
38
|
+
|
39
|
+
# cache of latest run; runs tests if cache is expired
|
40
|
+
# @see #latest_test_run_from_temp_cache
|
41
|
+
def latest_test_run_from_cache
|
42
|
+
Rails.cache.fetch("#{self.class}/#{__method__}", expires_in: QaServer::MonitorCacheService.cache_expiry, race_condition_ttl: 5.minutes, force: refresh_tests?) do
|
43
|
+
QaServer.config.monitor_logger.info("(#{self.class}##{__method__}) get latest run of monitoring tests - cache expired or refresh requested (force: #{refresh_tests?})")
|
44
|
+
QaServer::MonitorTestsJob.perform_later
|
32
45
|
scenario_run_registry_class.latest_run
|
33
46
|
end
|
34
47
|
end
|
35
48
|
|
36
49
|
# Sets @latest_summary [QaServer::ScenarioRunSummary]
|
37
50
|
def latest_summary
|
38
|
-
scenario_history_class.run_summary(scenario_run:
|
51
|
+
scenario_history_class.run_summary(scenario_run: latest_test_run, force: refresh_tests?)
|
39
52
|
end
|
40
53
|
|
41
54
|
def latest_failures
|
42
|
-
scenario_history_class.run_failures(run_id:
|
55
|
+
scenario_history_class.run_failures(run_id: latest_test_run.id, force: refresh_tests?)
|
43
56
|
end
|
44
57
|
|
45
58
|
# Sets @historical_data [Array<Hash>]
|
@@ -47,16 +60,15 @@ module QaServer
|
|
47
60
|
scenario_history_class.historical_summary(force: refresh_history?)
|
48
61
|
end
|
49
62
|
|
50
|
-
# Sets @
|
51
|
-
def
|
52
|
-
performance_history_class.
|
63
|
+
# Sets @performance_table_data [Hash<Hash>]
|
64
|
+
def performance_table_data
|
65
|
+
display_performance_datatable? ? performance_history_class.performance_table_data(force: refresh_performance?) : {}
|
53
66
|
end
|
54
67
|
|
55
|
-
def
|
56
|
-
return
|
57
|
-
|
58
|
-
|
59
|
-
:none
|
68
|
+
def update_performance_graphs
|
69
|
+
return unless display_performance_graph?
|
70
|
+
data = performance_history_class.performance_graph_data(force: refresh_performance?)
|
71
|
+
graphing_service_class.create_performance_graphs(performance_data: data)
|
60
72
|
end
|
61
73
|
|
62
74
|
def display_performance_datatable?
|
@@ -67,14 +79,6 @@ module QaServer
|
|
67
79
|
@display_performance_graph ||= QaServer.config.display_performance_graph?
|
68
80
|
end
|
69
81
|
|
70
|
-
def refresh_history
|
71
|
-
historical_summary_data(refresh: refresh_history?)
|
72
|
-
end
|
73
|
-
|
74
|
-
def refresh_performance
|
75
|
-
performance_data(refresh: refresh_performance?)
|
76
|
-
end
|
77
|
-
|
78
82
|
def refresh?
|
79
83
|
params.key? :refresh
|
80
84
|
end
|
@@ -98,5 +102,13 @@ module QaServer
|
|
98
102
|
return false unless refresh?
|
99
103
|
refresh_all? || params[:refresh].casecmp?('performance')
|
100
104
|
end
|
105
|
+
|
106
|
+
def log_header
|
107
|
+
QaServer.config.monitor_logger.debug("----------------------------------------------------------------------")
|
108
|
+
QaServer.config.monitor_logger.debug(" loading monitor status page")
|
109
|
+
QaServer.config.monitor_logger.debug("----------------------------------------------------------------------")
|
110
|
+
QaServer.config.monitor_logger.info("(#{self.class}##{__method__}) monitor status page request (refresh_tests? # #{refresh_tests?}, " \
|
111
|
+
"refresh_history? # #{refresh_history?}, refresh_performance? # #{refresh_performance?})")
|
112
|
+
end
|
101
113
|
end
|
102
114
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Job to run monitoring tests
|
3
|
+
module QaServer
|
4
|
+
class MonitorTestsJob < ApplicationJob
|
5
|
+
include QaServer::AuthorityValidationBehavior
|
6
|
+
|
7
|
+
queue_as :default
|
8
|
+
|
9
|
+
class_attribute :scenario_run_registry_class
|
10
|
+
self.scenario_run_registry_class = QaServer::ScenarioRunRegistry
|
11
|
+
|
12
|
+
# def perform(job_id:)
|
13
|
+
def perform
|
14
|
+
Rails.cache.fetch("QaServer::MonitorTestsController/latest_run", expires_in: QaServer::MonitorCacheService.cache_expiry, race_condition_ttl: 5.minutes, force: true) do
|
15
|
+
job_id = SecureRandom.uuid
|
16
|
+
monitor_tests_job_id = job_id unless monitor_tests_job_id
|
17
|
+
if monitor_tests_job_id == job_id # avoid race conditions
|
18
|
+
QaServer.config.monitor_logger.info("(#{self.class}##{__method__}-#{job_id}) RUNNING monitoring tests")
|
19
|
+
validate(authorities_list)
|
20
|
+
scenario_run_registry_class.save_run(scenarios_results: status_log.to_a)
|
21
|
+
QaServer.config.monitor_logger.info("(#{self.class}##{__method__}-#{job_id}) COMPLETED monitoring tests")
|
22
|
+
reset_monitor_tests_job_id
|
23
|
+
end
|
24
|
+
scenario_run_registry_class.latest_run
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# @return [String, Boolean] Returns job id of the job currently running tests; otherwise, false if tests are not running
|
31
|
+
def monitor_tests_job_id
|
32
|
+
Rails.cache.fetch("QaServer:monitor_tests-job_id", expires_in: 2.hours, race_condition_ttl: 5.minutes) { false }
|
33
|
+
end
|
34
|
+
|
35
|
+
# Set the id of the job that will run the tests.
|
36
|
+
# @param job_id [String] UUID for job running the tests
|
37
|
+
def monitor_tests_job_id=(job_id)
|
38
|
+
# check to see if there is a current job already running tests
|
39
|
+
current_job_id = Rails.cache.fetch("QaServer:monitor_tests-job_id", expires_in: 2.hours, race_condition_ttl: 30.seconds) { job_id }
|
40
|
+
|
41
|
+
# current_job_id may be false meaning tests are not currently running; in which case, it is ok to force set job_id
|
42
|
+
Rails.cache.fetch("QaServer:monitor_tests-job_id", expires_in: 2.hours, race_condition_ttl: 30.seconds, force: true) { job_id } unless current_job_id
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set job id for monitor tests to false indicating that tests are not currently running
|
46
|
+
def reset_monitor_tests_job_id
|
47
|
+
Rails.cache.fetch("QaServer:monitor_tests-job_id", expires_in: 2.hours, race_condition_ttl: 30.seconds, force: true) { false }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -7,7 +7,7 @@ module QaServer
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def new_entry(authority:, action:)
|
10
|
-
entry = { dt_stamp: QaServer.current_time,
|
10
|
+
entry = { dt_stamp: QaServer::TimeService.current_time,
|
11
11
|
authority: authority,
|
12
12
|
action: action }
|
13
13
|
id = SecureRandom.uuid
|
@@ -36,8 +36,7 @@ module QaServer
|
|
36
36
|
normalization_time_ms: entry[:normalization_time_ms])
|
37
37
|
@cache.delete(id)
|
38
38
|
end
|
39
|
-
|
40
|
-
Rails.logger.info("#{size_before - @cache.size} of #{size_before} performance data records were saved") if size_before.positive? && (size_before > @cache.size)
|
39
|
+
log_write_all("(#{self.class}##{__method__})", size_before, @cache.size)
|
41
40
|
end
|
42
41
|
|
43
42
|
def log(id:)
|
@@ -63,5 +62,14 @@ module QaServer
|
|
63
62
|
:graph_load_time_ms,
|
64
63
|
:normalization_time_ms]
|
65
64
|
end
|
65
|
+
|
66
|
+
def log_write_all(prefix, size_before, cache_size)
|
67
|
+
if size_before.positive?
|
68
|
+
QaServer.config.monitor_logger.warn("#{prefix} 0 of #{size_before} performance data records were saved") if size_before == cache_size
|
69
|
+
QaServer.config.monitor_logger.info("#{prefix} #{size_before - cache_size} of #{size_before} performance data records were saved") if size_before > cache_size
|
70
|
+
else
|
71
|
+
QaServer.config.monitor_logger.info("#{prefix} 0 of 0 performance data records were saved")
|
72
|
+
end
|
73
|
+
end
|
66
74
|
end
|
67
75
|
end
|
@@ -6,11 +6,9 @@ module QaServer
|
|
6
6
|
|
7
7
|
enum action: [:fetch, :search]
|
8
8
|
|
9
|
-
class_attribute :
|
10
|
-
self.
|
9
|
+
class_attribute :datatable_data_service_class, :graph_data_service_class
|
10
|
+
self.datatable_data_service_class = QaServer::PerformanceDatatableService
|
11
11
|
self.graph_data_service_class = QaServer::PerformanceGraphDataService
|
12
|
-
self.graphing_service_class = QaServer::PerformanceGraphingService
|
13
|
-
self.authority_list_class = QaServer::AuthorityListerService
|
14
12
|
|
15
13
|
class << self
|
16
14
|
include QaServer::PerformanceHistoryDataKeys
|
@@ -20,12 +18,30 @@ module QaServer
|
|
20
18
|
# @param action [Symbol] type of action being evaluated (e.g. :fetch, :search)
|
21
19
|
# @param dt_stamp [Time] defaults to current time in preferred time zone
|
22
20
|
# @return ActveRecord::Base for the new performance history record
|
23
|
-
def create_record(authority:, action:, dt_stamp: QaServer.current_time)
|
21
|
+
def create_record(authority:, action:, dt_stamp: QaServer::TimeService.current_time)
|
24
22
|
create(dt_stamp: dt_stamp,
|
25
23
|
authority: authority,
|
26
24
|
action: action)
|
27
25
|
end
|
28
26
|
|
27
|
+
# Performance data for a day, a month, a year, and all time for each authority.
|
28
|
+
# @param datatype [Symbol] what type of data should be calculated (e.g. :datatable, :graph, :all)
|
29
|
+
# @returns [Hash] performance statistics for the past 24 hours
|
30
|
+
# @example
|
31
|
+
# { all_authorities:
|
32
|
+
# { search:
|
33
|
+
# { retrieve_avg_ms: 12.3, graph_load_avg_ms: 2.1, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5,
|
34
|
+
# retrieve_10th_ms: 12.3, graph_load_10th_ms: 12.3, normalization_10th_ms: 4.2, full_request_10th_ms: 16.5,
|
35
|
+
# retrieve_90th_ms: 12.3, graph_load_90th_ms: 12.3, normalization_90th_ms: 4.2, full_request_90th_ms: 16.5 },
|
36
|
+
# fetch: { ... # same data as for search_stats },
|
37
|
+
# all: { ... # same data as for search_stats }
|
38
|
+
# },
|
39
|
+
# AGROVOC_LD4L_CACHE: { ... # same data for each authority }
|
40
|
+
# }
|
41
|
+
def performance_table_data(force: false)
|
42
|
+
datatable_data_service_class.calculate_datatable_data(force: force)
|
43
|
+
end
|
44
|
+
|
29
45
|
# Performance data for a day, a month, a year, and all time for each authority.
|
30
46
|
# @param datatype [Symbol] what type of data should be calculated (e.g. :datatable, :graph, :all)
|
31
47
|
# @returns [Hash] performance statistics for the past 24 hours
|
@@ -33,10 +49,6 @@ module QaServer
|
|
33
49
|
# { all_authorities:
|
34
50
|
# { search:
|
35
51
|
# {
|
36
|
-
# datatable_stats:
|
37
|
-
# { retrieve_avg_ms: 12.3, graph_load_avg_ms: 2.1, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5,
|
38
|
-
# retrieve_10th_ms: 12.3, graph_load_10th_ms: 12.3, normalization_10th_ms: 4.2, full_request_10th_ms: 16.5,
|
39
|
-
# retrieve_90th_ms: 12.3, graph_load_90th_ms: 12.3, normalization_90th_ms: 4.2, full_request_90th_ms: 16.5 }
|
40
52
|
# day:
|
41
53
|
# { 0: { hour: '1400', stats: { retrieve_avg_ms: 12.3, graph_load_avg_ms: 2.1, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }},
|
42
54
|
# 1: { hour: '1500', stats: { retrieve_avg_ms: 12.3, graph_load_avg_ms: 2.1, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }},
|
@@ -59,108 +71,14 @@ module QaServer
|
|
59
71
|
# 11: { month: '08-2019', stats: { retrieve_avg_ms: 12.3, graph_load_avg_ms: 2.1, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }}
|
60
72
|
# }
|
61
73
|
# },
|
62
|
-
# fetch: { ... # same data as for search_stats }
|
74
|
+
# fetch: { ... # same data as for search_stats },
|
63
75
|
# all: { ... # same data as for search_stats }
|
64
76
|
# },
|
65
77
|
# AGROVOC_LD4L_CACHE: { ... # same data for each authority }
|
66
78
|
# }
|
67
|
-
def
|
68
|
-
|
69
|
-
QaServer.config.performance_cache.write_all
|
70
|
-
data = calculate_data(datatype, force: force)
|
71
|
-
graphing_service_class.create_performance_graphs(performance_data: data) if calculate_graphdata? datatype
|
72
|
-
data
|
79
|
+
def performance_graph_data(force: false)
|
80
|
+
graph_data_service_class.calculate_graph_data(force: force)
|
73
81
|
end
|
74
|
-
|
75
|
-
private
|
76
|
-
|
77
|
-
def calculate_datatable?(datatype)
|
78
|
-
datatype == :datatable || datatype == :all
|
79
|
-
end
|
80
|
-
|
81
|
-
def calculate_graphdata?(datatype)
|
82
|
-
datatype == :graph || datatype == :all
|
83
|
-
end
|
84
|
-
|
85
|
-
def calculate_data(datatype, force:)
|
86
|
-
data = {}
|
87
|
-
auths = authority_list_class.authorities_list
|
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
|
-
data
|
91
|
-
end
|
92
|
-
|
93
|
-
def data_for_authority(authority_name: nil, datatype:, force:)
|
94
|
-
action_data = {}
|
95
|
-
[:search, :fetch, :all_actions].each do |action|
|
96
|
-
data = {}
|
97
|
-
data[FOR_DATATABLE] = data_table_stats(authority_name, action, force: force) if calculate_datatable?(datatype)
|
98
|
-
if calculate_graphdata?(datatype)
|
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
|
-
end
|
103
|
-
action_data[action] = data
|
104
|
-
end
|
105
|
-
action_data
|
106
|
-
end
|
107
|
-
|
108
|
-
# Get statistics for all available data.
|
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
|
112
|
-
# @returns [Hash] performance statistics for the datatable during the expected time period
|
113
|
-
# @example
|
114
|
-
# { retrieve_avg_ms: 12.3, graph_load_avg_ms: 2.1, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5,
|
115
|
-
# retrieve_10th_ms: 12.3, graph_load_10th_ms: 12.3, normalization_10th_ms: 4.2, full_request_10th_ms: 16.5,
|
116
|
-
# retrieve_90th_ms: 12.3, graph_load_90th_ms: 12.3, normalization_90th_ms: 4.2, full_request_90th_ms: 16.5 }
|
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
|
126
|
-
end
|
127
|
-
|
128
|
-
def expected_time_period
|
129
|
-
QaServer.config.performance_datatable_default_time_period
|
130
|
-
end
|
131
|
-
|
132
|
-
def records_for_last_24_hours(auth_name)
|
133
|
-
return unless expected_time_period == :day
|
134
|
-
end_hour = QaServer.current_time
|
135
|
-
start_hour = end_hour - 23.hours
|
136
|
-
where_clause = { dt_stamp: start_hour..end_hour }
|
137
|
-
records_for_authority(auth_name, where_clause)
|
138
|
-
end
|
139
|
-
|
140
|
-
def records_for_last_30_days(auth_name)
|
141
|
-
return unless expected_time_period == :month
|
142
|
-
end_day = QaServer.current_time
|
143
|
-
start_day = end_day - 29.days
|
144
|
-
where_clause = { dt_stamp: start_day..end_day }
|
145
|
-
records_for_authority(auth_name, where_clause)
|
146
|
-
end
|
147
|
-
|
148
|
-
def records_for_last_12_months(auth_name)
|
149
|
-
return unless expected_time_period == :year
|
150
|
-
end_month = QaServer.current_time
|
151
|
-
start_month = end_month - 11.months
|
152
|
-
where_clause = { dt_stamp: start_month..end_month }
|
153
|
-
records_for_authority(auth_name, where_clause)
|
154
|
-
end
|
155
|
-
|
156
|
-
def all_records(auth_name)
|
157
|
-
auth_name.nil? ? PerformanceHistory.all : where(authority: auth_name)
|
158
|
-
end
|
159
|
-
|
160
|
-
def records_for_authority(auth_name, where_clause)
|
161
|
-
where_clause[:authority] = auth_name unless auth_name.nil?
|
162
|
-
where(where_clause)
|
163
|
-
end
|
164
82
|
end
|
165
83
|
end
|
166
84
|
end
|