Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Initial sidekiq web extention commit * Add yardopts file * A simple web interface for unique digests * Adds a filter function for the web extension * Makes search form nicer * Remove unnecessary require * Add readme entry about the web extension * Styles * Remove unused files * Fix broken specs * Fix styles * Allow to complete in more fractions
- Loading branch information
Showing
27 changed files
with
491 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--no-private | ||
--exclude lib/sidekiq_unique_jobs/testing.rb | ||
--exclude lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb | ||
--exclude lib/sidekiq_unique_jobs/middleware.rb | ||
--exclude lib/sidekiq_unique_jobs/core_ext.rb | ||
--exclude lib/sidekiq_unique_jobs/cli.rb | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
# frozen_string_literal: true | ||
|
||
module SidekiqUniqueJobs | ||
# Utility module to help manage unique digests in redis. | ||
# | ||
# @author Mikael Henriksson <mikael@zoolutions.se> | ||
module Digests | ||
DEFAULT_COUNT = 1_000 | ||
SCAN_PATTERN = '*' | ||
CHUNK_SIZE = 100 | ||
|
||
include SidekiqUniqueJobs::Logging | ||
include SidekiqUniqueJobs::Connection | ||
extend self # rubocop:disable Style/ModuleFunction | ||
|
||
# Return unique digests matching pattern | ||
# | ||
# @param [String] pattern a pattern to match with | ||
# @param [Integer] count the maximum number to match | ||
# @return [Array<String>] with unique digests | ||
def all(pattern: SCAN_PATTERN, count: DEFAULT_COUNT) | ||
redis { |conn| conn.sscan_each(UNIQUE_SET, match: pattern, count: count).to_a } | ||
end | ||
|
||
# Get a total count of unique digests | ||
# | ||
# @return [Integer] number of digests | ||
def count | ||
redis { |conn| conn.scard(UNIQUE_SET) } | ||
end | ||
|
||
# Deletes unique digest either by a digest or pattern | ||
# | ||
# @param [String] digest the full digest to delete | ||
# @param [String] pattern a key pattern to match with | ||
# @param [Integer] count the maximum number | ||
# @raise [ArgumentError] when both pattern and digest are nil | ||
# @return [Array<String>] with unique digests | ||
def del(digest: nil, pattern: nil, count: DEFAULT_COUNT) | ||
return delete_by_pattern(pattern, count: count) if pattern | ||
return delete_by_digest(digest) if digest | ||
|
||
raise ArgumentError, 'either digest or pattern need to be provided' | ||
end | ||
|
||
private | ||
|
||
# Deletes unique digests by pattern | ||
# | ||
# @param [String] pattern a key pattern to match with | ||
# @param [Integer] count the maximum number | ||
# @return [Array<String>] with unique digests | ||
def delete_by_pattern(pattern, count: DEFAULT_COUNT) | ||
result, elapsed = timed do | ||
digests = all(pattern: pattern, count: count) | ||
batch_delete(digests) | ||
digests.size | ||
end | ||
|
||
log_info("#{__method__}(#{pattern}, count: #{count}) completed in #{elapsed}ms") | ||
|
||
result | ||
end | ||
|
||
# Get a total count of unique digests | ||
# | ||
# @param [String] digest a key pattern to match with | ||
def delete_by_digest(digest) | ||
result, elapsed = timed do | ||
Scripts.call(:delete_by_digest, nil, keys: [UNIQUE_SET, digest]) | ||
count | ||
end | ||
|
||
log_info("#{__method__}(#{digest}) completed in #{elapsed}ms") | ||
|
||
result | ||
end | ||
|
||
def batch_delete(digests) # rubocop:disable Metrics/MethodLength | ||
redis do |conn| | ||
digests.each_slice(CHUNK_SIZE) do |chunk| | ||
conn.pipelined do | ||
chunk.each do |digest| | ||
conn.del digest | ||
conn.srem(UNIQUE_SET, digest) | ||
conn.del("#{digest}:EXISTS") | ||
conn.del("#{digest}:GRABBED") | ||
conn.del("#{digest}:VERSION") | ||
conn.del("#{digest}:AVAILABLE") | ||
conn.del("#{digest}:RUN:EXISTS") | ||
conn.del("#{digest}:RUN:GRABBED") | ||
conn.del("#{digest}:RUN:VERSION") | ||
conn.del("#{digest}:RUN:AVAILABLE") | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
||
def timed | ||
start = current_time | ||
result = yield | ||
elapsed = (current_time - start).round(2) | ||
[result, elapsed] | ||
end | ||
|
||
def current_time | ||
Time.now | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# frozen_string_literal: true | ||
|
||
begin | ||
require 'sidekiq/web' | ||
rescue LoadError # rubocop:disable Lint/HandleExceptions | ||
# client-only usage | ||
end | ||
|
||
require_relative 'web/helpers' | ||
|
||
module SidekiqUniqueJobs | ||
# Utility module to help manage unique keys in redis. | ||
# Useful for deleting keys that for whatever reason wasn't deleted | ||
# | ||
# @author Mikael Henriksson <mikael@zoolutions.se> | ||
module Web | ||
def self.registered(app) # rubocop:disable Metrics/MethodLength | ||
app.helpers do | ||
include Web::Helpers | ||
end | ||
|
||
app.get '/unique_digests' do | ||
@total_size = Digests.count | ||
@filter = params[:filter] || '*' | ||
@filter = '*' if @filter == '' | ||
@count = (params[:count] || 100).to_i | ||
@unique_digests = Digests.all(pattern: @filter, count: @count) | ||
|
||
erb(unique_template(:unique_digests)) | ||
end | ||
|
||
app.get '/unique_digests/:digest' do | ||
@digest = params[:digest] | ||
@unique_keys = Util.keys("#{@digest}*", 1000) | ||
|
||
erb(unique_template(:unique_digest)) | ||
end | ||
|
||
app.get '/unique_digests/:digest/delete' do | ||
Digests.del(digest: params[:digest]) | ||
redirect_to :unique_digests | ||
end | ||
end | ||
end | ||
end | ||
|
||
if defined?(Sidekiq::Web) | ||
Sidekiq::Web.register SidekiqUniqueJobs::Web | ||
Sidekiq::Web.tabs['Unique Digests'] = 'unique_digests' | ||
# Sidekiq::Web.settings.locales << File.join(File.dirname(__FILE__), 'locales') | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# frozen_string_literal: true | ||
|
||
module SidekiqUniqueJobs | ||
module Web | ||
module Helpers | ||
VIEW_PATH = File.expand_path('../web/views', __dir__) | ||
|
||
def filtering(pattern, count) | ||
SidekiqUniqueJobs::Util.keys(pattern, count) | ||
end | ||
|
||
def unique_template(name) | ||
File.open(File.join(VIEW_PATH, "#{name}.erb")).read | ||
end | ||
|
||
def redirect_to(subpath) | ||
if respond_to?(:to) | ||
# Sinatra-based web UI | ||
redirect to(subpath) | ||
else | ||
# Non-Sinatra based web UI (Sidekiq 4.2+) | ||
redirect "#{root_path}#{subpath}" | ||
end | ||
end | ||
|
||
def safe_relative_time(time) | ||
time = if time.is_a?(Numeric) | ||
Time.at(time) | ||
else | ||
Time.parse(time) | ||
end | ||
|
||
relative_time(time) | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.