sidekiq 8.0.2 → 8.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Changes.md +18 -0
- data/lib/active_job/queue_adapters/sidekiq_adapter.rb +93 -57
- data/lib/sidekiq/job/iterable.rb +3 -0
- data/lib/sidekiq/middleware/current_attributes.rb +4 -1
- data/lib/sidekiq/profiler.rb +16 -3
- data/lib/sidekiq/rails.rb +43 -65
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/action.rb +19 -0
- data/lib/sidekiq/web/application.rb +12 -4
- data/lib/sidekiq/web/config.rb +1 -1
- data/lib/sidekiq/web/helpers.rb +23 -18
- data/lib/sidekiq/web.rb +1 -0
- data/web/assets/javascripts/dashboard.js +1 -1
- data/web/assets/stylesheets/style.css +13 -2
- data/web/locales/it.yml +7 -0
- data/web/views/layout.erb +1 -0
- data/web/views/scheduled.erb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70244790b6f984dfb4da9922e5971f3072479bce2f484ca3ab3982108906e6d0
|
4
|
+
data.tar.gz: 77b5d8e952603bebfe6e703b0f92df3cf4b78be6caf7e46fb46e5376c02c45c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c347f189e4ed255a1de061afa5c08bf73b3d77f83d853669e09c9b7e06f430958d1db4e3aa9a6ae3a9abad5802c3872f050ae43b2db014105633c45be4cfaa0
|
7
|
+
data.tar.gz: 0fca2e77cfd25ab7ccc6be20edeb8a0c09056c8bb0bde03de5ff415a5ca15f55668e1c662a2f91c1dfe8ed074ae5d106d95b1d3a04e32fa1d86606aa35c06645
|
data/Changes.md
CHANGED
@@ -2,6 +2,24 @@
|
|
2
2
|
|
3
3
|
[Sidekiq Changes](https://github.com/sidekiq/sidekiq/blob/main/Changes.md) | [Sidekiq Pro Changes](https://github.com/sidekiq/sidekiq/blob/main/Pro-Changes.md) | [Sidekiq Enterprise Changes](https://github.com/sidekiq/sidekiq/blob/main/Ent-Changes.md)
|
4
4
|
|
5
|
+
8.0.4
|
6
|
+
----------
|
7
|
+
|
8
|
+
- Adjust Rails integration for various edge cases [6713]
|
9
|
+
- Flush job iteration state when an error is raised [#6704]
|
10
|
+
- Update Accept-Language parsing in Web UI [#6721]
|
11
|
+
- Remove fixed-width in Web UI [#6686]
|
12
|
+
- Adjust CSRF middleware ordering [#6688]
|
13
|
+
- Support proxies when POSTing profiles to profiler.firefox.com [#6687]
|
14
|
+
- Dont swallow NoMethodErrors in CurrentAttributes [#6685]
|
15
|
+
|
16
|
+
8.0.3
|
17
|
+
----------
|
18
|
+
|
19
|
+
- Configure Vernier output directory [#6674]
|
20
|
+
- Rework Rails integration [#6669]
|
21
|
+
- Implement flash messages for the Web UI [#6675]
|
22
|
+
|
5
23
|
8.0.2
|
6
24
|
----------
|
7
25
|
|
@@ -1,75 +1,111 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
remove_const(:SidekiqAdapter) if const_defined?(:SidekiqAdapter)
|
3
|
+
begin
|
4
|
+
gem "activejob", ">= 7.0"
|
5
|
+
require "active_job"
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
# To use Sidekiq set the queue_adapter config to +:sidekiq+.
|
11
|
-
#
|
12
|
-
# Rails.application.config.active_job.queue_adapter = :sidekiq
|
13
|
-
class SidekiqAdapter
|
14
|
-
# Defines whether enqueuing should happen implicitly to after commit when called
|
15
|
-
# from inside a transaction.
|
7
|
+
module Sidekiq
|
8
|
+
module ActiveJob
|
16
9
|
# @api private
|
17
|
-
|
18
|
-
|
19
|
-
end
|
10
|
+
class Wrapper
|
11
|
+
include Sidekiq::Job
|
20
12
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
wrapped: job.class,
|
25
|
-
queue: job.queue_name
|
26
|
-
).perform_async(job.serialize)
|
13
|
+
def perform(job_data)
|
14
|
+
::ActiveJob::Base.execute(job_data.merge("provider_job_id" => jid))
|
15
|
+
end
|
27
16
|
end
|
17
|
+
end
|
18
|
+
end
|
28
19
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
20
|
+
unless ActiveJob::Base.respond_to?(:sidekiq_options)
|
21
|
+
# By including the Options module, we allow AJs to directly control sidekiq features
|
22
|
+
# via the *sidekiq_options* class method and, for instance, not use AJ's retry system.
|
23
|
+
# AJ retries don't show up in the Sidekiq UI Retries tab, don't save any error data, can't be
|
24
|
+
# manually retried, don't automatically die, etc.
|
25
|
+
#
|
26
|
+
# class SomeJob < ActiveJob::Base
|
27
|
+
# queue_as :default
|
28
|
+
# sidekiq_options retry: 3, backtrace: 10
|
29
|
+
# def perform
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
ActiveJob::Base.include Sidekiq::Job::Options
|
33
|
+
end
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
immediate_jobs, scheduled_jobs = same_class_and_queue_jobs.partition { |job| job.scheduled_at.nil? }
|
35
|
+
# Patch the ActiveJob module
|
36
|
+
module ActiveJob
|
37
|
+
module QueueAdapters
|
38
|
+
# Explicitly remove the implementation existing in older Rails.
|
39
|
+
remove_const(:SidekiqAdapter) if const_defined?(:SidekiqAdapter)
|
43
40
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
41
|
+
# Sidekiq adapter for Active Job
|
42
|
+
#
|
43
|
+
# To use Sidekiq set the queue_adapter config to +:sidekiq+.
|
44
|
+
#
|
45
|
+
# Rails.application.config.active_job.queue_adapter = :sidekiq
|
46
|
+
class SidekiqAdapter
|
47
|
+
# Defines whether enqueuing should happen implicitly to after commit when called
|
48
|
+
# from inside a transaction.
|
49
|
+
# @api private
|
50
|
+
def enqueue_after_transaction_commit?
|
51
|
+
true
|
52
|
+
end
|
53
|
+
|
54
|
+
# @api private
|
55
|
+
def enqueue(job)
|
56
|
+
job.provider_job_id = Sidekiq::ActiveJob::Wrapper.set(
|
57
|
+
wrapped: job.class,
|
58
|
+
queue: job.queue_name
|
59
|
+
).perform_async(job.serialize)
|
60
|
+
end
|
61
|
+
|
62
|
+
# @api private
|
63
|
+
def enqueue_at(job, timestamp)
|
64
|
+
job.provider_job_id = Sidekiq::ActiveJob::Wrapper.set(
|
65
|
+
wrapped: job.class,
|
66
|
+
queue: job.queue_name
|
67
|
+
).perform_at(timestamp, job.serialize)
|
68
|
+
end
|
53
69
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
70
|
+
# @api private
|
71
|
+
def enqueue_all(jobs)
|
72
|
+
enqueued_count = 0
|
73
|
+
jobs.group_by(&:class).each do |job_class, same_class_jobs|
|
74
|
+
same_class_jobs.group_by(&:queue_name).each do |queue, same_class_and_queue_jobs|
|
75
|
+
immediate_jobs, scheduled_jobs = same_class_and_queue_jobs.partition { |job| job.scheduled_at.nil? }
|
76
|
+
|
77
|
+
if immediate_jobs.any?
|
78
|
+
jids = Sidekiq::Client.push_bulk(
|
79
|
+
"class" => Sidekiq::ActiveJob::Wrapper,
|
80
|
+
"wrapped" => job_class,
|
81
|
+
"queue" => queue,
|
82
|
+
"args" => immediate_jobs.map { |job| [job.serialize] }
|
83
|
+
)
|
84
|
+
enqueued_count += jids.compact.size
|
85
|
+
end
|
86
|
+
|
87
|
+
if scheduled_jobs.any?
|
88
|
+
jids = Sidekiq::Client.push_bulk(
|
89
|
+
"class" => Sidekiq::ActiveJob::Wrapper,
|
90
|
+
"wrapped" => job_class,
|
91
|
+
"queue" => queue,
|
92
|
+
"args" => scheduled_jobs.map { |job| [job.serialize] },
|
93
|
+
"at" => scheduled_jobs.map { |job| job.scheduled_at&.to_f }
|
94
|
+
)
|
95
|
+
enqueued_count += jids.compact.size
|
96
|
+
end
|
63
97
|
end
|
64
98
|
end
|
99
|
+
enqueued_count
|
65
100
|
end
|
66
|
-
enqueued_count
|
67
|
-
end
|
68
101
|
|
69
|
-
|
70
|
-
|
71
|
-
|
102
|
+
# Defines a class alias for backwards compatibility with enqueued Active Job jobs.
|
103
|
+
# @api private
|
104
|
+
class JobWrapper < Sidekiq::ActiveJob::Wrapper
|
105
|
+
end
|
72
106
|
end
|
73
107
|
end
|
74
108
|
end
|
109
|
+
rescue Gem::LoadError
|
110
|
+
# ActiveJob not available or version requirement not met
|
75
111
|
end
|
data/lib/sidekiq/job/iterable.rb
CHANGED
@@ -71,11 +71,14 @@ module Sidekiq
|
|
71
71
|
retried = false
|
72
72
|
|
73
73
|
begin
|
74
|
+
set_succeeded = false
|
74
75
|
klass.set(attrs) do
|
76
|
+
set_succeeded = true
|
75
77
|
wrap(klass_attrs, &block)
|
76
78
|
end
|
77
79
|
rescue NoMethodError
|
78
|
-
|
80
|
+
# Don't retry if the no method error didn't come from current attributes
|
81
|
+
raise if retried || set_succeeded
|
79
82
|
|
80
83
|
# It is possible that the `CurrentAttributes` definition
|
81
84
|
# was changed before the job started processing.
|
data/lib/sidekiq/profiler.rb
CHANGED
@@ -13,6 +13,7 @@ module Sidekiq
|
|
13
13
|
include Sidekiq::Component
|
14
14
|
def initialize(config)
|
15
15
|
@config = config
|
16
|
+
@vernier_output_dir = ENV.fetch("VERNIER_OUTPUT_DIR") { Dir.tmpdir }
|
16
17
|
end
|
17
18
|
|
18
19
|
def call(job, &block)
|
@@ -22,7 +23,6 @@ module Sidekiq
|
|
22
23
|
type = job["class"]
|
23
24
|
jid = job["jid"]
|
24
25
|
started_at = Time.now
|
25
|
-
options = DEFAULT_OPTIONS.merge((job["profiler_options"] || {}).transform_keys!(&:to_sym))
|
26
26
|
|
27
27
|
rundata = {
|
28
28
|
started_at: started_at.to_i,
|
@@ -30,13 +30,17 @@ module Sidekiq
|
|
30
30
|
type: type,
|
31
31
|
jid: jid,
|
32
32
|
# .gz extension tells Vernier to compress the data
|
33
|
-
filename:
|
33
|
+
filename: File.join(
|
34
|
+
@vernier_output_dir,
|
35
|
+
"#{token}-#{type}-#{jid}-#{started_at.strftime("%Y%m%d-%H%M%S")}.json.gz"
|
36
|
+
)
|
34
37
|
}
|
38
|
+
profiler_options = profiler_options(job, rundata)
|
35
39
|
|
36
40
|
require "vernier"
|
37
41
|
begin
|
38
42
|
a = Time.now
|
39
|
-
rc = Vernier.profile(**
|
43
|
+
rc = Vernier.profile(**profiler_options, &block)
|
40
44
|
b = Time.now
|
41
45
|
|
42
46
|
# Failed jobs will raise an exception on previous line and skip this
|
@@ -55,5 +59,14 @@ module Sidekiq
|
|
55
59
|
FileUtils.rm_f(rundata[:filename])
|
56
60
|
end
|
57
61
|
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def profiler_options(job, rundata)
|
66
|
+
profiler_options = (job["profiler_options"] || {}).transform_keys(&:to_sym)
|
67
|
+
profiler_options[:mode] = profiler_options[:mode].to_sym if profiler_options[:mode]
|
68
|
+
|
69
|
+
DEFAULT_OPTIONS.merge(profiler_options, {out: rundata[:filename]})
|
70
|
+
end
|
58
71
|
end
|
59
72
|
end
|
data/lib/sidekiq/rails.rb
CHANGED
@@ -1,84 +1,62 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "sidekiq/job"
|
4
|
-
|
4
|
+
require_relative "../active_job/queue_adapters/sidekiq_adapter"
|
5
5
|
|
6
6
|
module Sidekiq
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class Rails < ::Rails::Engine
|
19
|
-
class Reloader
|
20
|
-
def initialize(app = ::Rails.application)
|
21
|
-
@app = app
|
22
|
-
end
|
23
|
-
|
24
|
-
def call
|
25
|
-
params = (::Rails::VERSION::STRING >= "7.1") ? {source: "job.sidekiq"} : {}
|
26
|
-
@app.reloader.wrap(**params) do
|
27
|
-
yield
|
7
|
+
begin
|
8
|
+
gem "railties", ">= 7.0"
|
9
|
+
require "rails"
|
10
|
+
|
11
|
+
class Rails < ::Rails::Engine
|
12
|
+
class Reloader
|
13
|
+
def initialize(app = ::Rails.application)
|
14
|
+
@app = app
|
28
15
|
end
|
29
|
-
end
|
30
16
|
|
31
|
-
|
32
|
-
|
33
|
-
|
17
|
+
def call
|
18
|
+
params = (::Rails::VERSION::STRING >= "7.1") ? {source: "job.sidekiq"} : {}
|
19
|
+
@app.reloader.wrap(**params) do
|
20
|
+
yield
|
21
|
+
end
|
22
|
+
end
|
34
23
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
24
|
+
def inspect
|
25
|
+
"#<Sidekiq::Rails::Reloader @app=#{@app.class.name}>"
|
26
|
+
end
|
39
27
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
# manually retried, don't automatically die, etc.
|
44
|
-
#
|
45
|
-
# class SomeJob < ActiveJob::Base
|
46
|
-
# queue_as :default
|
47
|
-
# sidekiq_options retry: 3, backtrace: 10
|
48
|
-
# def perform
|
49
|
-
# end
|
50
|
-
# end
|
51
|
-
initializer "sidekiq.active_job_integration" do
|
52
|
-
ActiveSupport.on_load(:active_job) do
|
53
|
-
require_relative "../active_job/queue_adapters/sidekiq_adapter"
|
54
|
-
include ::Sidekiq::Job::Options unless respond_to?(:sidekiq_options)
|
28
|
+
def to_hash
|
29
|
+
{app: @app.class.name}
|
30
|
+
end
|
55
31
|
end
|
56
|
-
end
|
57
32
|
|
58
|
-
|
59
|
-
|
60
|
-
|
33
|
+
initializer "sidekiq.backtrace_cleaner" do
|
34
|
+
Sidekiq.configure_server do |config|
|
35
|
+
config[:backtrace_cleaner] = ->(backtrace) { ::Rails.backtrace_cleaner.clean(backtrace) }
|
36
|
+
end
|
61
37
|
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# This hook happens after all initializers are run, just before returning
|
65
|
-
# from config/environment.rb back to sidekiq/cli.rb.
|
66
|
-
#
|
67
|
-
# None of this matters on the client-side, only within the Sidekiq process itself.
|
68
|
-
config.after_initialize do
|
69
|
-
Sidekiq.configure_server do |config|
|
70
|
-
config[:reloader] = Sidekiq::Rails::Reloader.new
|
71
38
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
39
|
+
# This hook happens after all initializers are run, just before returning
|
40
|
+
# from config/environment.rb back to sidekiq/cli.rb.
|
41
|
+
#
|
42
|
+
# None of this matters on the client-side, only within the Sidekiq process itself.
|
43
|
+
config.after_initialize do
|
44
|
+
Sidekiq.configure_server do |config|
|
45
|
+
config[:reloader] = Sidekiq::Rails::Reloader.new
|
46
|
+
|
47
|
+
# This is the integration code necessary so that if a job uses `Rails.logger.info "Hello"`,
|
48
|
+
# it will appear in the Sidekiq console with all of the job context.
|
49
|
+
unless ::Rails.logger == config.logger || ::ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout)
|
50
|
+
if ::Rails.logger.respond_to?(:broadcast_to)
|
51
|
+
::Rails.logger.broadcast_to(config.logger)
|
52
|
+
else
|
53
|
+
::Rails.logger.extend(::ActiveSupport::Logger.broadcast(config.logger))
|
54
|
+
end
|
79
55
|
end
|
80
56
|
end
|
81
57
|
end
|
82
58
|
end
|
59
|
+
rescue Gem::LoadError
|
60
|
+
# Rails not available or version requirement not met
|
83
61
|
end
|
84
62
|
end
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web/action.rb
CHANGED
@@ -70,6 +70,25 @@ module Sidekiq
|
|
70
70
|
env["rack.session"]
|
71
71
|
end
|
72
72
|
|
73
|
+
def logger
|
74
|
+
Sidekiq.logger
|
75
|
+
end
|
76
|
+
|
77
|
+
# flash { "Some message to show on redirect" }
|
78
|
+
def flash
|
79
|
+
msg = yield
|
80
|
+
logger.info msg
|
81
|
+
session[:flash] = msg
|
82
|
+
end
|
83
|
+
|
84
|
+
def flash?
|
85
|
+
session&.[](:flash)
|
86
|
+
end
|
87
|
+
|
88
|
+
def get_flash
|
89
|
+
@flash ||= session.delete(:flash)
|
90
|
+
end
|
91
|
+
|
73
92
|
def erb(content, options = {})
|
74
93
|
if content.is_a? Symbol
|
75
94
|
unless respond_to?(:"_erb_#{content}")
|
@@ -325,6 +325,8 @@ module Sidekiq
|
|
325
325
|
get "/stats" do
|
326
326
|
sidekiq_stats = Sidekiq::Stats.new
|
327
327
|
redis_stats = redis_info.slice(*REDIS_KEYS)
|
328
|
+
redis_stats["store_name"] = store_name
|
329
|
+
redis_stats["store_version"] = store_version
|
328
330
|
json(
|
329
331
|
sidekiq: {
|
330
332
|
processed: sidekiq_stats.processed,
|
@@ -360,10 +362,16 @@ module Sidekiq
|
|
360
362
|
unless sid
|
361
363
|
require "net/http"
|
362
364
|
data = Sidekiq.redis { |c| c.hget(key, "data") }
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
365
|
+
|
366
|
+
store_uri = URI(store)
|
367
|
+
http = Net::HTTP.new(store_uri.host, store_uri.port)
|
368
|
+
http.use_ssl = store_uri.scheme == "https"
|
369
|
+
request = Net::HTTP::Post.new(store_uri.request_uri)
|
370
|
+
request.body = data
|
371
|
+
request["Accept"] = "application/vnd.firefox-profiler+json;version=1.0"
|
372
|
+
request["User-Agent"] = "Sidekiq #{Sidekiq::VERSION} job profiler"
|
373
|
+
|
374
|
+
resp = http.request(request)
|
367
375
|
# https://raw.githubusercontent.com/firefox-devtools/profiler-server/master/tools/decode_jwt_payload.py
|
368
376
|
rawjson = resp.body.split(".")[1].unpack1("m")
|
369
377
|
sid = Sidekiq.load_json(rawjson)["profileToken"]
|
data/lib/sidekiq/web/config.rb
CHANGED
data/lib/sidekiq/web/helpers.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require "uri"
|
4
4
|
require "yaml"
|
5
|
-
require "cgi"
|
5
|
+
require "cgi/escape"
|
6
6
|
|
7
7
|
module Sidekiq
|
8
8
|
# These methods are available to pages within the Web UI and UI extensions.
|
@@ -165,7 +165,10 @@ module Sidekiq
|
|
165
165
|
text_direction == "rtl"
|
166
166
|
end
|
167
167
|
|
168
|
-
# See https://www.
|
168
|
+
# See https://www.rfc-editor.org/rfc/rfc9110.html#section-12.5.4
|
169
|
+
# Returns an array of language tags ordered by their quality value
|
170
|
+
#
|
171
|
+
# Inspiration taken from https://github.com/iain/http_accept_language/blob/master/lib/http_accept_language/parser.rb
|
169
172
|
def user_preferred_languages
|
170
173
|
languages = env["HTTP_ACCEPT_LANGUAGE"]
|
171
174
|
languages.to_s.gsub(/\s+/, "").split(",").map { |language|
|
@@ -180,28 +183,30 @@ module Sidekiq
|
|
180
183
|
|
181
184
|
# Given an Accept-Language header like "fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4,ru;q=0.2"
|
182
185
|
# this method will try to best match the available locales to the user's preferred languages.
|
183
|
-
#
|
184
|
-
# Inspiration taken from https://github.com/iain/http_accept_language/blob/master/lib/http_accept_language/parser.rb
|
185
186
|
def locale
|
186
187
|
# session[:locale] is set via the locale selector from the footer
|
187
188
|
@locale ||= if (l = session&.fetch(:locale, nil)) && available_locales.include?(l)
|
188
189
|
l
|
189
190
|
else
|
191
|
+
matched_locale = nil
|
192
|
+
# Attempt to find a case-insensitive exact match first
|
193
|
+
user_preferred_languages.each do |preferred|
|
194
|
+
# We only care about the language and primary subtag
|
195
|
+
# "en-GB-oxendict" becomes "en-GB"
|
196
|
+
language_tag = preferred.split("-")[0..1].join("-")
|
197
|
+
matched_locale = available_locales.find { |available_locale| available_locale.casecmp?(language_tag) }
|
198
|
+
break if matched_locale
|
199
|
+
end
|
190
200
|
|
191
|
-
|
192
|
-
matched_locale = user_preferred_languages.find { |preferred|
|
193
|
-
available_locales.include?(preferred) if preferred.length == 5
|
194
|
-
}
|
195
|
-
|
196
|
-
matched_locale ||= user_preferred_languages.map { |preferred|
|
197
|
-
preferred_language = preferred.split("-", 2).first
|
198
|
-
|
199
|
-
lang_group = available_locales.select { |available|
|
200
|
-
preferred_language == available.split("-", 2).first
|
201
|
-
}
|
201
|
+
return matched_locale if matched_locale
|
202
202
|
|
203
|
-
|
204
|
-
|
203
|
+
# Find the first base language match
|
204
|
+
# "en-US,es-MX;q=0.9" matches "en"
|
205
|
+
user_preferred_languages.each do |preferred|
|
206
|
+
base_language = preferred.split("-", 2).first
|
207
|
+
matched_locale = available_locales.find { |available_locale| available_locale.casecmp?(base_language) }
|
208
|
+
break if matched_locale
|
209
|
+
end
|
205
210
|
|
206
211
|
matched_locale || "en"
|
207
212
|
end
|
@@ -372,7 +377,7 @@ module Sidekiq
|
|
372
377
|
elsif rss_kb < 10_000_000
|
373
378
|
"#{number_with_delimiter((rss_kb / 1024.0).to_i)} MB"
|
374
379
|
else
|
375
|
-
"#{number_with_delimiter(
|
380
|
+
"#{number_with_delimiter(rss_kb / (1024.0 * 1024.0), precision: 1)} GB"
|
376
381
|
end
|
377
382
|
end
|
378
383
|
|
data/lib/sidekiq/web.rb
CHANGED
@@ -109,6 +109,7 @@ module Sidekiq
|
|
109
109
|
cascade: true,
|
110
110
|
header_rules: rules
|
111
111
|
m.each { |middleware, block| use(*middleware, &block) }
|
112
|
+
use CsrfProtection unless $TESTING # rubocop:disable Style/GlobalVars
|
112
113
|
run Sidekiq::Web::Application.new(self.class)
|
113
114
|
end
|
114
115
|
end
|
@@ -11,7 +11,7 @@ var updateStatsSummary = function(data) {
|
|
11
11
|
}
|
12
12
|
|
13
13
|
var updateRedisStats = function(data) {
|
14
|
-
document.getElementById('redis_version').innerText = data.
|
14
|
+
document.getElementById('redis_version').innerText = data.store_version;
|
15
15
|
document.getElementById('uptime_in_days').innerText = data.uptime_in_days;
|
16
16
|
document.getElementById('connected_clients').innerText = data.connected_clients;
|
17
17
|
document.getElementById('used_memory_human').innerText = data.used_memory_human;
|
@@ -69,7 +69,7 @@ body {
|
|
69
69
|
|
70
70
|
.container {
|
71
71
|
margin: 0 auto;
|
72
|
-
max-width: 1440px;
|
72
|
+
/* max-width: 1440px; */
|
73
73
|
padding: var(--space-2x);
|
74
74
|
}
|
75
75
|
|
@@ -90,6 +90,7 @@ code {
|
|
90
90
|
font-family: var(--font-mono);
|
91
91
|
font-size: var(--font-size-small);
|
92
92
|
padding: var(--space-1-2);
|
93
|
+
word-wrap: anywhere;
|
93
94
|
}
|
94
95
|
|
95
96
|
time { color: var(--color-text-light); }
|
@@ -437,7 +438,10 @@ article .count {
|
|
437
438
|
}
|
438
439
|
|
439
440
|
/* table */
|
440
|
-
.table_container {
|
441
|
+
.table_container {
|
442
|
+
overflow-x: auto;
|
443
|
+
margin-bottom: var(--space-2x);
|
444
|
+
}
|
441
445
|
|
442
446
|
.table_container + form,
|
443
447
|
.table_container + input,
|
@@ -748,3 +752,10 @@ body > footer .nav {
|
|
748
752
|
.w-50 {
|
749
753
|
width: 50%;
|
750
754
|
}
|
755
|
+
|
756
|
+
.flash {
|
757
|
+
width: 100%;
|
758
|
+
text-align: center;
|
759
|
+
padding: 20px;
|
760
|
+
background: var(--color-success);
|
761
|
+
}
|
data/web/locales/it.yml
CHANGED
@@ -35,6 +35,7 @@ it:
|
|
35
35
|
Jobs: Lavori
|
36
36
|
Kill: Uccidere
|
37
37
|
KillAll: Uccidere tutti
|
38
|
+
Language: Lingua
|
38
39
|
LastRetry: Ultimo tentativo
|
39
40
|
Latency: Latenza
|
40
41
|
LivePoll: Live poll
|
@@ -54,6 +55,7 @@ it:
|
|
54
55
|
PeakMemoryUsage: Memoria utilizzata (max.)
|
55
56
|
Plugins: Plugins
|
56
57
|
PollingInterval: Intervallo di polling
|
58
|
+
PollingIntervalMilliseconds: Intervallo di polling in millisecondi
|
57
59
|
Process: Processo
|
58
60
|
Processed: Processato
|
59
61
|
Processes: Processi
|
@@ -99,3 +101,8 @@ it:
|
|
99
101
|
NoJobMetricsFound: Metriche recenti di lavoro non trovate
|
100
102
|
Filter: Filtro
|
101
103
|
AnyJobContent: Qualsiasi contenuto di lavoro
|
104
|
+
Profiles: Profili
|
105
|
+
Data: Dati
|
106
|
+
View: Vista
|
107
|
+
Token: Token
|
108
|
+
ElapsedTime: Tempo Trascorso
|
data/web/views/layout.erb
CHANGED
data/web/views/scheduled.erb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.0.
|
4
|
+
version: 8.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Perham
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-05-28 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: redis-client
|