Skip to content
Snippets Groups Projects
Commit bf0331dc authored by Francisco Javier López's avatar Francisco Javier López Committed by Douwe Maan
Browse files

Resolve "DashboardController#activity.json is slow due to SQL"

parent 34a205b3
No related branches found
No related tags found
No related merge requests found
Showing
with 120 additions and 49 deletions
Loading
Loading
@@ -39,7 +39,7 @@ module NotesActions
@note = Notes::CreateService.new(note_project, current_user, create_params).execute
 
if @note.is_a?(Note)
Banzai::NoteRenderer.render([@note], @project, current_user)
Notes::RenderService.new(current_user).execute([@note], @project)
end
 
respond_to do |format|
Loading
Loading
@@ -52,7 +52,7 @@ module NotesActions
@note = Notes::UpdateService.new(project, current_user, note_params).execute(note)
 
if @note.is_a?(Note)
Banzai::NoteRenderer.render([@note], @project, current_user)
Notes::RenderService.new(current_user).execute([@note], @project)
end
 
respond_to do |format|
Loading
Loading
Loading
Loading
@@ -3,7 +3,7 @@ module RendersNotes
preload_noteable_for_regular_notes(notes)
preload_max_access_for_authors(notes, @project)
preload_first_time_contribution_for_authors(noteable, notes)
Banzai::NoteRenderer.render(notes, @project, current_user)
Notes::RenderService.new(current_user).execute(notes, @project)
 
notes
end
Loading
Loading
Loading
Loading
@@ -57,5 +57,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
@events = EventCollection
.new(projects, offset: params[:offset].to_i, filter: event_filter)
.to_a
Events::RenderService.new(current_user).execute(@events, atom_request: request.format.atom?)
end
end
Loading
Loading
@@ -32,6 +32,8 @@ class DashboardController < Dashboard::ApplicationController
@events = EventCollection
.new(projects, offset: params[:offset].to_i, filter: @event_filter)
.to_a
Events::RenderService.new(current_user).execute(@events)
end
 
def set_show_full_reference
Loading
Loading
Loading
Loading
@@ -155,6 +155,8 @@ class GroupsController < Groups::ApplicationController
@events = EventCollection
.new(@projects, offset: params[:offset].to_i, filter: event_filter)
.to_a
Events::RenderService.new(current_user).execute(@events, atom_request: request.format.atom?)
end
 
def user_actions
Loading
Loading
Loading
Loading
@@ -300,6 +300,8 @@ class ProjectsController < Projects::ApplicationController
@events = EventCollection
.new(projects, offset: params[:offset].to_i, filter: event_filter)
.to_a
Events::RenderService.new(current_user).execute(@events, atom_request: request.format.atom?)
end
 
def project_params
Loading
Loading
Loading
Loading
@@ -108,6 +108,8 @@ class UsersController < ApplicationController
.references(:project)
.with_associations
.limit_recent(20, params[:offset])
Events::RenderService.new(current_user).execute(@events, atom_request: request.format.atom?)
end
 
def load_projects
Loading
Loading
Loading
Loading
@@ -172,16 +172,6 @@ module EventsHelper
end
end
 
def event_note(text, options = {})
text = first_line_in_markdown(text, 150, options)
sanitize(
text,
tags: %w(a img gl-emoji b pre code p span),
attributes: Rails::Html::WhiteListSanitizer.allowed_attributes + ['style', 'data-src', 'data-name', 'data-unicode-version']
)
end
def event_commit_title(message)
message ||= ''
(message.split("\n").first || "").truncate(70)
Loading
Loading
Loading
Loading
@@ -69,10 +69,16 @@ module MarkupHelper
# as Markdown. HTML tags in the parsed output are not counted toward the
# +max_chars+ limit. If the length limit falls within a tag's contents, then
# the tag contents are truncated without removing the closing tag.
def first_line_in_markdown(text, max_chars = nil, options = {})
md = markdown(text, options).strip
def first_line_in_markdown(object, attribute, max_chars = nil, options = {})
md = markdown_field(object, attribute, options)
 
truncate_visible(md, max_chars || md.length) if md.present?
text = truncate_visible(md, max_chars || md.length) if md.present?
sanitize(
text,
tags: %w(a img gl-emoji b pre code p span),
attributes: Rails::Html::WhiteListSanitizer.allowed_attributes + ['style', 'data-src', 'data-name', 'data-unicode-version']
)
end
 
def markdown(text, context = {})
Loading
Loading
@@ -83,15 +89,17 @@ module MarkupHelper
prepare_for_rendering(html, context)
end
 
def markdown_field(object, field)
def markdown_field(object, field, context = {})
object = object.for_display if object.respond_to?(:for_display)
redacted_field_html = object.try(:"redacted_#{field}_html")
 
return '' unless object.present?
return redacted_field_html if redacted_field_html
 
html = Banzai.render_field(object, field)
prepare_for_rendering(html, object.banzai_render_context(field))
html = Banzai.render_field(object, field, context)
context.reverse_merge!(object.banzai_render_context(field)) if object.respond_to?(:banzai_render_context)
prepare_for_rendering(html, context)
end
 
def markup(file_name, text, context = {})
Loading
Loading
class BaseRenderer
attr_reader :current_user
def initialize(current_user = nil)
@current_user = current_user
end
end
module Events
class RenderService < BaseRenderer
def execute(events, atom_request: false)
events.map(&:note).compact.group_by(&:project).each do |project, notes|
render_notes(notes, project, atom_request)
end
end
private
def render_notes(notes, project, atom_request)
Notes::RenderService.new(current_user).execute(notes, project, render_options(atom_request))
end
def render_options(atom_request)
return {} unless atom_request
{ only_path: false, xhtml: true }
end
end
end
module Banzai
module NoteRenderer
module Notes
class RenderService < BaseRenderer
# Renders a collection of Note instances.
#
# notes - The notes to render.
# project - The project to use for redacting.
# user - The user viewing the notes.
# path - The request path.
# wiki - The project's wiki.
# git_ref - The current Git reference.
def self.render(notes, project, user = nil, path = nil, wiki = nil, git_ref = nil)
renderer = ObjectRenderer.new(project,
user,
requested_path: path,
project_wiki: wiki,
ref: git_ref)
# Possible options:
# requested_path - The request path.
# project_wiki - The project's wiki.
# ref - The current Git reference.
# only_path - flag to turn relative paths into absolute ones.
# xhtml - flag to save the html in XHTML
def execute(notes, project, **opts)
renderer = Banzai::ObjectRenderer.new(project, current_user, **opts)
 
renderer.render(notes, :note)
end
Loading
Loading
Loading
Loading
@@ -36,7 +36,7 @@
.todo-body
.todo-note
.md
= event_note(todo.body, project: todo.project)
= first_line_in_markdown(todo, :body, 150, project: todo.project)
 
- if todo.pending?
.todo-actions
Loading
Loading
%div{ xmlns: "http://www.w3.org/1999/xhtml" }
= markdown(note.note, pipeline: :atom, project: note.project, author: note.author)
= markdown_field(note, :note)
Loading
Loading
@@ -10,7 +10,7 @@
.event-body
.event-note
.md
= event_note(event.target.note, project: event.project)
= first_line_in_markdown(event.target, :note, 150, project: event.project)
- note = event.target
- if note.attachment.url
- if note.attachment.image?
Loading
Loading
---
title: Improve DashboardController#activity.json performance
merge_request: 14985
author:
type: performance
Loading
Loading
@@ -77,7 +77,6 @@ def instrument_classes(instrumentation)
 
instrumentation.instrument_instance_methods(Banzai::ObjectRenderer)
instrumentation.instrument_instance_methods(Banzai::Redactor)
instrumentation.instrument_methods(Banzai::NoteRenderer)
 
[Issuable, Mentionable, Participable].each do |klass|
instrumentation.instrument_instance_methods(klass)
Loading
Loading
Loading
Loading
@@ -3,8 +3,8 @@ module Banzai
Renderer.render(text, context)
end
 
def self.render_field(object, field)
Renderer.render_field(object, field)
def self.render_field(object, field, context = {})
Renderer.render_field(object, field, context)
end
 
def self.cache_collection_render(texts_and_contexts)
Loading
Loading
require 'uri'
module Banzai
module Filter
# HTML filter that converts relative urls into absolute ones.
class AbsoluteLinkFilter < HTML::Pipeline::Filter
def call
return doc unless context[:only_path] == false
doc.search('a.gfm').each do |el|
process_link_attr el.attribute('href')
end
doc
end
protected
def process_link_attr(html_attr)
return if html_attr.blank?
return if html_attr.value.start_with?('//')
uri = URI(html_attr.value)
html_attr.value = absolute_link_attr(uri) if uri.relative?
rescue URI::Error
# noop
end
def absolute_link_attr(uri)
URI.join(Gitlab.config.gitlab.url, uri).to_s
end
end
end
end
Loading
Loading
@@ -311,30 +311,6 @@ module Banzai
def project_refs_cache
RequestStore[:banzai_project_refs] ||= {}
end
def cached_call(request_store_key, cache_key, path: [])
if RequestStore.active?
cache = RequestStore[request_store_key] ||= Hash.new do |hash, key|
hash[key] = Hash.new { |h, k| h[k] = {} }
end
cache = cache.dig(*path) if path.any?
get_or_set_cache(cache, cache_key) { yield }
else
yield
end
end
def get_or_set_cache(cache, key)
if cache.key?(key)
cache[key]
else
value = yield
cache[key] = value if key.present?
value
end
end
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment