require 'rake' require 'rake/tasklib' module RailsConnector # The CacheGarbageCollectorTask allows to remove old cache files from the Rails Connector cache # storage path. By default, a maximum of +DEFAULT_MAX_FILE_INODES+ file inodes that were accessed # lately are kept in the cache directory. All other files and empty directories are removed. Log # output is written to the Rails environment log file. # # @example Running the garbage collector with default settings # # bundle exec rake infopark:cache:gc # # @example Changing the maximum number of file inodes # # bundle exec rake infopark:cache:gc MAX_FILE_INODES=5000 class CacheGarbageCollectorTask < ::Rake::TaskLib DEFAULT_MAX_FILE_INODES = 100000 attr_accessor :max_file_inodes def initialize @max_file_inodes = (ENV['MAX_FILE_INODES'] || DEFAULT_MAX_FILE_INODES).to_i namespace :infopark do namespace :cache do desc "Cap number of cache file inodes at #{@max_file_inodes}. Use MAX_FILE_INODES to specify the maximum. (default: #{DEFAULT_MAX_FILE_INODES})" task gc: :environment do run_gc end end end end private def run_gc announce "Cap number of cache file inodes at #{max_file_inodes} in #{cache_path}." directories = [] file_inode_count = 0 delta_disk_space = 0 delta_count = 0 cache_entries.each do |cache_entry| begin stat = File.stat(cache_entry) if stat.file? file_inode_count += 1 next if file_inode_count <= max_file_inodes File.delete(cache_entry) delta_disk_space += stat.size delta_count += 1 elsif stat.directory? directories << cache_entry end rescue Errno::ENOENT end end directories.sort.reverse_each do |dirname| begin Dir.rmdir(dirname) delta_count += 1 rescue Errno::ENOTEMPTY, Errno::ENOENT end end announce "Done. Removed #{delta_count} entries. Saved at least #{delta_disk_space} Bytes." end def cache_path CmsCacheStorage.backend_cache.cache_path end def cache_entries Dir["#{cache_path}/**/*"].sort_by do |file| begin -File.atime(file).to_i rescue Errno::ENOENT # If such file or directory does not exist, sort it as if the last # access time is very long ago. 0 end end end def announce(message) message = "[#{Time.now.iso8601}] #{message}" Rails.logger.info(message) end end end