Skip to content

Commit

Permalink
Merge pull request #191 from alphagov/resolver-cache
Browse files Browse the repository at this point in the history
Fix memory leak in components
  • Loading branch information
tijmenb committed Feb 27, 2017
2 parents c2a6b26 + 4e0a7f4 commit 83287c1
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
* Fix memory leak in components

# 10.1.2

* Bugfix for request URI's encoded as ASCII
Expand Down
6 changes: 0 additions & 6 deletions lib/slimmer/component_resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@ module Slimmer
class ComponentResolver < ::ActionView::Resolver
TEST_TAG_NAME = 'test-govuk-component'

def self.caching
# this turns off the default ActionView::Resolver caching which caches
# all templates for the duration of the current process in production
false
end

def find_templates(name, prefix, partial, details, outside_app_allowed = false)
return [] unless prefix == 'govuk_component'

Expand Down
26 changes: 25 additions & 1 deletion lib/slimmer/govuk_components.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,41 @@ def self.included into

# @private
def add_govuk_components
append_view_path Slimmer::ComponentResolver.new
append_view_path GovukComponents.expiring_resolver_cache.resolver

return if slimmer_backend_included?
I18n.backend = I18n::Backend::Chain.new(I18n.backend, Slimmer::I18nBackend.new)
end

# @private
def self.expiring_resolver_cache
@expiring_resolver_cache ||= TimedExpirationResolverCache.new
end

private

def slimmer_backend_included?
I18n.backend.is_a?(I18n::Backend::Chain) &&
I18n.backend.backends.any? { |b| b.is_a? Slimmer::I18nBackend }
end

# Slimmer::ComponentResolver instantiates a lot of large objects and leaks
# memory. This class will cache the resolver so that it doesn't have to
# create new ActionView::Template objects for each request. The cache is
# timed to allow frontends to pick up changes made to components in `static`.
class TimedExpirationResolverCache
def initialize
@cache_last_reset = Time.now
end

def resolver
if (@cache_last_reset + Slimmer::CACHE_TTL) < Time.now
@resolver = nil
@cache_last_reset = Time.now
end

@resolver ||= Slimmer::ComponentResolver.new
end
end
end
end

0 comments on commit 83287c1

Please sign in to comment.