diff --git a/notifier/migration.rb b/notifier/migration.rb index 32ae3fff874068a4be8ab54d45f4cd23cdbaa8c4..94ee04ce7ee59c061d140a81742212e8716a19e2 100644 --- a/notifier/migration.rb +++ b/notifier/migration.rb @@ -1,11 +1,14 @@ # frozen_string_literal: true class Migration - REGULAR_MIGRATION_GUIDANCE_SECONDS = (3 * 60) - POST_DEPLOY_MIGRATION_GUIDANCE_SECONDS = (10 * 60) + REGULAR_MIGRATION_GUIDANCE_SECONDS = 3.minutes.freeze + POST_DEPLOY_MIGRATION_GUIDANCE_SECONDS = 10.minutes.freeze + SRE_NOTIFICATION_GUIDANCE = 20.minutes.freeze TYPE_REGULAR = 'regular' TYPE_POST_DEPLOY = 'post_deploy' - TIMING_GUIDELINES = "https://docs.gitlab.com/ee/development/database_review.html#timing-guidelines-for-migrations" + TIMING_GUIDELINES = 'https://docs.gitlab.com/ee/development/database_review.html#timing-guidelines-for-migrations' + POST_DEPLOY_MIGRATION_GUIDE = 'https://docs.gitlab.com/ee/development/post_deployment_migrations.html' + BACKGROUND_MIGRATION_GUIDE = 'https://docs.gitlab.com/ee/development/background_migrations.html' attr_accessor :version, :path, :name, :statistics, :total_database_size_change, :queries, :type, :walltime, :intro_on_current_branch, :success, @@ -40,6 +43,10 @@ class Migration raise 'Unknown migration type' end + def sre_should_be_informed? + walltime > SRE_NOTIFICATION_GUIDANCE + end + def exceeds_time_guidance? walltime > time_guidance end @@ -60,19 +67,41 @@ class Migration "#{version} - #{name}" end + def walltime_minutes + "#{walltime.in_minutes.round(2)}min" + end + + def time_guidance_minutes + "#{time_guidance.in_minutes.round(2)}min" + end + def warnings warnings = queries_with_warnings.map { |q| q.warning(name_formatted) } warnings << "#{name_formatted} did not complete successfully, check the job log for details" unless success? - if exceeds_time_guidance? - warnings << "#{name_formatted} [exceeded timing guidelines](#{TIMING_GUIDELINES})."\ - "This migration should not exceed #{time_guidance}s, but was #{walltime}s" + if sre_should_be_informed? + warnings << "#{name_formatted} took #{walltime_minutes}. Please add a comment that mentions Release "\ + "Managers (`@gitlab-org/release/managers`) so they are informed." end + warnings << time_remedy if exceeds_time_guidance? + warnings end + def time_remedy + if type == TYPE_REGULAR && walltime < POST_DEPLOY_MIGRATION_GUIDANCE_SECONDS + "#{name_formatted} may need a [post-deploy migration](#{POST_DEPLOY_MIGRATION_GUIDE}) "\ + "to comply with [timing guidelines](#{TIMING_GUIDELINES}). It took #{walltime_minutes}, "\ + "but should not exceed #{time_guidance_minutes}" + else + "#{name_formatted} may need a [background migration](#{BACKGROUND_MIGRATION_GUIDE}) to "\ + "comply with [timing guidelines](#{TIMING_GUIDELINES}). It took #{walltime_minutes}, "\ + "but should not exceed #{time_guidance_minutes}" + end + end + def warning? !success? || exceeds_time_guidance? || has_queries_with_warnings? end @@ -85,7 +114,7 @@ class Migration @was_run = true @total_database_size_change = stats['total_database_size_change'] - @walltime = stats['walltime'] + @walltime = stats['walltime'].seconds @success = stats['success'] @statistics = stats init_queries(stats) diff --git a/notifier/query.rb b/notifier/query.rb index c9126a52040ea995ab9a259ab16c586a6f7f1731..0f12e5c3acffc79a36231d3904a56d34d252749f 100644 --- a/notifier/query.rb +++ b/notifier/query.rb @@ -5,7 +5,7 @@ require_relative 'query_execution' class Query QUERY_GUIDANCE_MILLISECONDS = 100 - CONCURRENT_QUERY_GUIDANCE_MILLISECONDS = 5 * 60 * 1000 + CONCURRENT_QUERY_GUIDANCE_MILLISECONDS = 5.minutes.in_milliseconds TIMING_GUIDELINES = 'https://docs.gitlab.com/ee/development/query_performance.html#timing-guidelines-for-queries' # rubocop:disable Layout/LineLength @@ -37,7 +37,6 @@ class Query def formatted_query Niceql::Prettifier.prettify_sql(query) - .gsub(' ', ' ') .gsub('/*', '/*') .gsub('*/', '*/') .gsub("\n", '
') @@ -62,15 +61,16 @@ class Query def timing if calls == 1 - "it was #{max_time}" + "it was #{max_time.truncate(2)}" else - "the longest was #{max_time}ms, and the average was #{mean_time}ms" + "the longest was #{max_time.truncate(2)}ms, and the average was #{mean_time.truncate(2)}ms" end end def warning(migration_name) "#{migration_name} had a query that [exceeded timing guidelines](#{TIMING_GUIDELINES}). Run time "\ - "should not exceed #{time_guidance}ms, but #{timing}
#{formatted_query}
" + "should not exceed #{time_guidance}ms, but was #{timing}ms. Please consider possible options to "\ + "improve the query performance.
#{formatted_query}
" end def excluded? diff --git a/notifier/spec/fixtures/migration-testing/expected-comment.txt b/notifier/spec/fixtures/migration-testing/expected-comment.txt index 350c9912415a9cd94de46252972eb461dd1552fe..297daee3a77b2430eb8018e0e8adebdaf827afaf 100644 --- a/notifier/spec/fixtures/migration-testing/expected-comment.txt +++ b/notifier/spec/fixtures/migration-testing/expected-comment.txt @@ -1,15 +1,20 @@ ### Database migrations -| | 1 Warnings | +| | 4 Warnings | | --------- | -------------------- | -| :warning: | 20210604233157 - MigrationThrowsException did not complete successfully, check the job log for details | +| :warning: | 20200325104758 - AddTestMigrationThatExceedsTimingForRegularButNotPost may need a
[post-deploy migration](https://docs.gitlab.com/ee/development/post_deployment_migrations.html) to comply with [timing guidelines](https://docs.gitlab.com/ee/development/database_review.html#timing-guidelines-for-migrations). It took 5.08min, but should not exceed 3.0min | +| :warning: | 20201015154529 - AddMigrationThatRequiresBackground took 25.02min. Please add a comment that
mentions Release Managers (`@gitlab-org/release/managers`) so they are informed. | +| :warning: | 20201015154529 - AddMigrationThatRequiresBackground may need a [background migration](https://docs.gitlab.com/ee/development/background_migrations.html) to
comply with [timing guidelines](https://docs.gitlab.com/ee/development/database_review.html#timing-guidelines-for-migrations). It took 25.02min, but should not exceed 10.0min | +| :warning: | 20210604233157 - MigrationThrowsException did not complete successfully, check the job log
for details | Migrations included in this change have been executed on gitlab.com data for testing purposes. For details, please see the [migration testing pipeline](https://gitlab.com/gitlab-org/database-team/gitlab-com-database-testing/-/pipelines/4711) (limited access). | Migration | Type | Total runtime | Result | DB size change | | --------- | ---- | ------------- | ------ | -------------- | +| 20200325104758 - AddTestMigrationThatExceedsTimingForRegularButNotPost | Regular | 306.0 s | :warning: | +32.00 KiB | | 20210602144718 - CreateTestTable | Regular | 1.8 s | :white_check_mark: | +40.00 KiB | +| 20201015154529 - AddMigrationThatRequiresBackground | Post deploy | 1502.0 s | :warning: | +32.00 KiB | | 20210604232017 - DropTestTable | Post deploy | 1.2 s | :white_check_mark: | -24.00 KiB | | 20210604233157 - MigrationThrowsException | Post deploy | 0.9 s | :boom: | +0.00 B | @@ -27,6 +32,13 @@ Migrations included in this change have been executed on gitlab.com data for tes +#### :warning: Migration: 20200325104758 - AddTestMigrationThatExceedsTimingForRegularButNotPost + +* Type: Regular +* Duration: 306.0 s +* Database size change: +32.00 KiB + + #### Migration: 20210602144718 - CreateTestTable * Type: Regular @@ -35,9 +47,9 @@ Migrations included in this change have been executed on gitlab.com data for tes | Query | Calls | Total Time | Max Time | Mean Time | Rows | | ----- | ----- | ---------- | -------- | --------- | ---- | -|
CREATE TABLE "test_tables" ("id" bigserial primary key, "stars" bigint DEFAULT 0 NOT NULL, "created_at" timestamp(6) NOT NULL, "updated_at" timestamp(6) NOT NULL, "title" text, "notes" text) /*application:test*/
| 1 | 71.1 ms | 71.1 ms | 71.1 ms | 0 | -|
ALTER TABLE "test_tables" ADD CONSTRAINT "check_0770ba173a" CHECK (char_length("title") <= 128), ADD CONSTRAINT "check_9cfc473dbc" CHECK (char_length("notes") <= 1024)
/*application:test*/
| 1 | 6.4 ms | 6.4 ms | 6.4 ms | 0 | -|
SELECT $1::regtype::oid
| 1 | 0.0 ms | 0.0 ms | 0.0 ms | 1 | +|
CREATE TABLE "test_tables" ("id" bigserial primary key, "stars" bigint DEFAULT 0 NOT NULL, "created_at" timestamp(6) NOT NULL, "updated_at" timestamp(6) NOT NULL, "title" text, "notes" text) /*application:test*/
| 1 | 71.1 ms | 71.1 ms | 71.1 ms | 0 | +|
ALTER TABLE "test_tables" ADD CONSTRAINT "check_0770ba173a" CHECK (char_length("title") <= 128), ADD CONSTRAINT "check_9cfc473dbc" CHECK (char_length("notes") <= 1024)
/*application:test*/
| 1 | 6.4 ms | 6.4 ms | 6.4 ms | 0 | +|
SELECT $1::regtype::oid
| 1 | 0.0 ms | 0.0 ms | 0.0 ms | 1 |
Histogram for CreateTestTable @@ -52,6 +64,13 @@ Migrations included in this change have been executed on gitlab.com data for tes
+#### :warning: Migration: 20201015154529 - AddMigrationThatRequiresBackground + +* Type: Post deploy +* Duration: 1502.0 s +* Database size change: +32.00 KiB + + #### Migration: 20210604232017 - DropTestTable * Type: Post deploy @@ -60,7 +79,7 @@ Migrations included in this change have been executed on gitlab.com data for tes | Query | Calls | Total Time | Max Time | Mean Time | Rows | | ----- | ----- | ---------- | -------- | --------- | ---- | -|
DROP TABLE "test_tables" /*application:test*/
| 1 | 5.7 ms | 5.7 ms | 5.7 ms | 0 | +|
DROP TABLE "test_tables" /*application:test*/
| 1 | 5.7 ms | 5.7 ms | 5.7 ms | 0 |
Histogram for DropTestTable @@ -116,12 +135,17 @@ Migrations included in this change have been executed on gitlab.com data for tes --- Brought to you by [gitlab-org/database-team/gitlab-com-database-testing](https://gitlab.com/gitlab-org/database-team/gitlab-com-database-testing). [Epic](https://gitlab.com/groups/gitlab-org/database-team/-/epics/9) - \ No newline at end of file diff --git a/notifier/spec/fixtures/migration-testing/migration-stats.json b/notifier/spec/fixtures/migration-testing/migration-stats.json index ae821b4d43d4d7479907bec1820687841448a2a9..36d531a3e8ef13ea104f34cdb7f7b6b0c05d8f74 100644 --- a/notifier/spec/fixtures/migration-testing/migration-stats.json +++ b/notifier/spec/fixtures/migration-testing/migration-stats.json @@ -263,6 +263,20 @@ } ] }, + { + "migration": 20200325104758, + "walltime": 305.9509822260588408, + "success": true, + "total_database_size_change": 32768, + "query_statistics": [] + }, + { + "migration": 20201015154529, + "walltime": 1501.9509822260588408, + "success": true, + "total_database_size_change": 32768, + "query_statistics": [] + }, { "migration": 20210604232017, "walltime": 1.1652476582676172, diff --git a/notifier/spec/fixtures/migration-testing/migrations.json b/notifier/spec/fixtures/migration-testing/migrations.json index b04a25c2f17af1c04a66c9dba1bf78e2d161a9d8..a3bb79cca296adeddf58e1cdae2be16fe27982a4 100644 --- a/notifier/spec/fixtures/migration-testing/migrations.json +++ b/notifier/spec/fixtures/migration-testing/migrations.json @@ -1,4 +1,25 @@ { + "20200323011225": { + "version": 20200323011225, + "path": "db/post_migrate/20200323011225_complete_migrate_security_scans.rb", + "name": "CompleteMigrateSecurityScans", + "type": "post_deploy", + "intro_on_current_branch": false + }, + "20201015154527": { + "version": 20201015154527, + "path": "db/post_migrate/20201015154527_add_index_on_services_for_usage_data.rb", + "name": "AddIndexOnServicesForUsageData", + "type": "post_deploy", + "intro_on_current_branch": false + }, + "20201015154529": { + "version": 20201015154529, + "path": "db/post_migrate/20201015154529_add_migration_that_requires_background.rb", + "name": "AddMigrationThatRequiresBackground", + "type": "post_deploy", + "intro_on_current_branch": true + }, "20210604232017": { "version": 20210604232017, "path": "db/post_migrate/20210604232017_drop_test_table.rb", @@ -13,6 +34,34 @@ "type": "post_deploy", "intro_on_current_branch": true }, + "20200325104755": { + "version": 20200325104755, + "path": "db/migrate/20200325104755_add_push_rules_id_to_project_settings.rb", + "name": "AddPushRulesIdToProjectSettings", + "type": "regular", + "intro_on_current_branch": false + }, + "20200325104758": { + "version": 20200325104758, + "path": "db/migrate/20200325104758_add_migration_that_exceeds_timing_for_regular_but_not_post.rb", + "name": "AddTestMigrationThatExceedsTimingForRegularButNotPost", + "type": "regular", + "intro_on_current_branch": true + }, + "20200911120132": { + "version": 20200911120132, + "path": "db/migrate/20200911120132_create_pages_deployments.rb", + "name": "CreatePagesDeployments", + "type": "regular", + "intro_on_current_branch": false + }, + "20200415161206": { + "version": 20200415161206, + "path": "db/migrate/20200415161206_remove_not_null_uploads_constraint.rb", + "name": "RemoveNotNullUploadsConstraint", + "type": "regular", + "intro_on_current_branch": false + }, "20210602144718": { "version": 20210602144718, "path": "db/migrate/20210602144718_create_test_table.rb", diff --git a/notifier/spec/warnings_spec.rb b/notifier/spec/warnings_spec.rb index 4060077457270d2c0767af0223b4bb39b26bb2de..78606b3cf50e03405deb5a8fe41247ace497986e 100644 --- a/notifier/spec/warnings_spec.rb +++ b/notifier/spec/warnings_spec.rb @@ -14,8 +14,8 @@ RSpec.describe Warnings do describe '#render' do it 'renders a few things' do - allow(migration).to receive(:exceeds_time_guidance?).and_return(true) allow(migration).to receive(:success?).and_return(false) + allow(migration).to receive(:walltime).and_return(Migration::SRE_NOTIFICATION_GUIDANCE * 2) allow(migration).to receive(:queries_with_warnings).and_return( [Query.new({ "query" => "select * from users limit 1000 /*application:test*/", @@ -27,9 +27,10 @@ RSpec.describe Warnings do })]) expect(subject.render).to include('did not complete') - expect(subject.render).to include('This migration should not exceed') - expect(subject.render).to include('should not exceed 100ms') - expect(subject.render).to include('222.49203') + expect(subject.render).to include('[background migration]') + expect(subject.render).to include('[post-deploy migration]') + expect(subject.render).to include('(`@gitlab-org/release/managers`)') + expect(subject.render).to include('222.49') end it 'excludes migrations not introduced on current branch' do diff --git a/notifier/templates/warnings.erb b/notifier/templates/warnings.erb index a63b7012f7340a2a2a8a5928213c27647c8c8df6..b0d7004ebaa746ed5927b9197f68542f50ca0e09 100644 --- a/notifier/templates/warnings.erb +++ b/notifier/templates/warnings.erb @@ -1,5 +1,5 @@ | | <%= count %> Warnings | | --------- | -------------------- | -% all.each do |warning| +% with_line_breaks.each do |warning| | :warning: | <%= warning %> | % end diff --git a/notifier/warnings.rb b/notifier/warnings.rb index 8e2b9484f22ab980f518c9aa5b509c937c71419d..a44421e68a6a629f29e367886da82b711261d332 100644 --- a/notifier/warnings.rb +++ b/notifier/warnings.rb @@ -15,6 +15,18 @@ class Warnings @all.any? end + def with_line_breaks + all.map do |warning| + warning.split(' ').reduce('') do |final, word| + if word.sub(/]\(.*\)/, '').length + (final.split('
').last&.sub(/]\(.*\)/, '')&.length || 0) > 100 + final = "#{final}
" + end + + "#{final} #{word}" + end + end + end + def render return '' unless any?