sidekiq 8.0.0.beta2 → 8.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1701d726f9433f505053b19c5c708c76ec16cc815cef96492f085e914f52c016
4
- data.tar.gz: 81504bd7aad6e5815027008a4d61908d898742b4f64ceb518e1fff078de228a6
3
+ metadata.gz: e6ce813e475bd69e3cb05f0ebe216e1dcbd6b4865584a4761c889a97761d5fe1
4
+ data.tar.gz: 855e4b4db0b7c080f9a4347c338eff1c4b62be91e233d0e20447b15a3251756a
5
5
  SHA512:
6
- metadata.gz: 96c78d5229328a1fcfc4663afc4c32437ec8438e246641739409876f608aa90ad19aca7185f0ae7b1e2a26291e105bf3fccda538dde508d1aaea854c4fcc9ef6
7
- data.tar.gz: cbb162697c348a02d4b9cd35a8f215d6b42e381ba1236ad4c5b41ccbcd55f4a8a601087c7bb4cbf3f9c63447c2406544b248465735398d66e55e981577dcbbc9
6
+ metadata.gz: 20f3dfd6b5e9aba7f8d2a0ef0fb9bef6ee7918aa31a8deee0bc592dcd957e44c08ca5d6a30e16064c81a5f68bc571fe8585c2e3ba453a81db0d565862e67454b
7
+ data.tar.gz: cdfea6f26e591ac0fb7c4bfe8874d8272615b27bfdd91daef13d1620e902fd5ba8a3c818d70a5729a89104c6ae7ac576c0f0df65717f514999d5c1c651605bd8
data/Changes.md CHANGED
@@ -2,7 +2,7 @@
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
- HEAD / main
5
+ 8.0.0
6
6
  ----------
7
7
 
8
8
  - **WARNING** The underlying class name for Active Jobs has changed from `ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper` to `Sidekiq::ActiveJob::Wrapper`.
@@ -26,14 +26,25 @@ HEAD / main
26
26
  - Job tags now allow custom CSS display [#6595]
27
27
  - The Web UI's language picker now shows options in the native language
28
28
  - Remove global variable usage within the codebase
29
+ - Colorize and adjust logging for easier reading
29
30
  - Adjust Sidekiq's default thread priority to -1 for a 50ms timeslice.
30
31
  This can help avoid TimeoutErrors when Sidekiq is overloaded. [#6543]
31
- - Support: Redis 7.2+, Ruby 3.2+, Rails 7.0+
32
+ - Use `Logger#with_level`, remove Sidekiq's custom impl
33
+ - Remove `base64` gem dependency
34
+ - Support: (Dragonfly 1.27+, Valkey 7.2+, Redis 7.2+), Ruby 3.2+, Rails 7.0+
35
+
36
+ 7.3.10
37
+ ----------
38
+
39
+ - Deprecate Redis :password as a String to avoid log disclosure. [#6625]
40
+ Use a Proc instead: `config.redis = { password: ->(username) { "password" } }`
32
41
 
33
42
  7.3.9
34
43
  ----------
35
44
 
36
45
  - Only require activejob if necessary [#6584]
46
+ You might get `uninitialized constant Sidekiq::ActiveJob` if you
47
+ `require 'sidekiq'` before `require 'rails'`.
37
48
  - Fix iterable job cancellation [#6589]
38
49
  - Web UI accessibility improvements [#6604]
39
50
 
data/README.md CHANGED
@@ -13,7 +13,7 @@ same process. Sidekiq can be used by any Ruby application.
13
13
  Requirements
14
14
  -----------------
15
15
 
16
- - Redis: Redis 7.2+, Valkey 7.2+ or Dragonfly 1.13+
16
+ - Redis: Redis 7.2+, Valkey 7.2+ or Dragonfly 1.27+
17
17
  - Ruby: MRI 3.2+ or JRuby 9.4+.
18
18
 
19
19
  Sidekiq 8.0 supports Rails and Active Job 7.0+.
@@ -26,16 +26,16 @@ module Sidekiq
26
26
  # If we're using a wrapper class, like ActiveJob, use the "wrapped"
27
27
  # attribute to expose the underlying thing.
28
28
  h = {
29
- class: job_hash["display_class"] || job_hash["wrapped"] || job_hash["class"],
30
- jid: job_hash["jid"]
29
+ jid: job_hash["jid"],
30
+ class: job_hash["display_class"] || job_hash["wrapped"] || job_hash["class"]
31
31
  }
32
32
  h[:bid] = job_hash["bid"] if job_hash.has_key?("bid")
33
33
  h[:tags] = job_hash["tags"] if job_hash.has_key?("tags")
34
34
 
35
35
  Thread.current[:sidekiq_context] = h
36
36
  level = job_hash["log_level"]
37
- if level && @logger.respond_to?(:log_at)
38
- @logger.log_at(level, &block)
37
+ if level
38
+ @logger.with_level(level, &block)
39
39
  else
40
40
  yield
41
41
  end
@@ -22,88 +22,41 @@ module Sidekiq
22
22
  end
23
23
  end
24
24
 
25
- module LoggingUtils
26
- LEVELS = {
27
- "debug" => 0,
28
- "info" => 1,
29
- "warn" => 2,
30
- "error" => 3,
31
- "fatal" => 4
32
- }
33
- LEVELS.default_proc = proc do |_, level|
34
- puts("Invalid log level: #{level.inspect}")
35
- nil
36
- end
37
-
38
- LEVELS.each do |level, numeric_level|
39
- define_method(:"#{level}?") do
40
- local_level.nil? ? super() : local_level <= numeric_level
41
- end
42
- end
43
-
44
- def local_level
45
- Thread.current[:sidekiq_log_level]
46
- end
47
-
48
- def local_level=(level)
49
- case level
50
- when Integer
51
- Thread.current[:sidekiq_log_level] = level
52
- when Symbol, String
53
- Thread.current[:sidekiq_log_level] = LEVELS[level.to_s]
54
- when nil
55
- Thread.current[:sidekiq_log_level] = nil
56
- else
57
- raise ArgumentError, "Invalid log level: #{level.inspect}"
58
- end
59
- end
60
-
61
- def level
62
- local_level || super
63
- end
64
-
65
- # Change the thread-local level for the duration of the given block.
66
- def log_at(level)
67
- old_local_level = local_level
68
- self.local_level = level
69
- yield
70
- ensure
71
- self.local_level = old_local_level
72
- end
73
- end
74
-
75
25
  class Logger < ::Logger
76
- include LoggingUtils
77
-
78
26
  module Formatters
27
+ COLORS = {
28
+ "DEBUG" => "\e[1;32mDEBUG\e[0m", # green
29
+ "INFO" => "\e[1;34mINFO \e[0m", # blue
30
+ "WARN" => "\e[1;33mWARN \e[0m", # yellow
31
+ "ERROR" => "\e[1;31mERROR\e[0m", # red
32
+ "FATAL" => "\e[1;35mFATAL\e[0m" # pink
33
+ }
79
34
  class Base < ::Logger::Formatter
80
35
  def tid
81
36
  Thread.current["sidekiq_tid"] ||= (Thread.current.object_id ^ ::Process.pid).to_s(36)
82
37
  end
83
38
 
84
39
  def format_context(ctxt = Sidekiq::Context.current)
85
- if ctxt.size > 0
86
- ctxt.map { |k, v|
87
- case v
88
- when Array
89
- "#{k}=#{v.join(",")}"
90
- else
91
- "#{k}=#{v}"
92
- end
93
- }.join(" ")
94
- end
40
+ (ctxt.size == 0) ? "" : " #{ctxt.map { |k, v|
41
+ case v
42
+ when Array
43
+ "#{k}=#{v.join(",")}"
44
+ else
45
+ "#{k}=#{v}"
46
+ end
47
+ }.join(" ")}"
95
48
  end
96
49
  end
97
50
 
98
51
  class Pretty < Base
99
52
  def call(severity, time, program_name, message)
100
- "#{time.utc.iso8601(3)} pid=#{::Process.pid} tid=#{tid} #{format_context} #{severity}: #{message}\n"
53
+ "#{Formatters::COLORS[severity]} #{time.utc.iso8601(3)} pid=#{::Process.pid} tid=#{tid}#{format_context}: #{message}\n"
101
54
  end
102
55
  end
103
56
 
104
57
  class WithoutTimestamp < Pretty
105
58
  def call(severity, time, program_name, message)
106
- "pid=#{::Process.pid} tid=#{tid} #{format_context} #{severity}: #{message}\n"
59
+ "#{Formatters::COLORS[severity]} pid=#{::Process.pid} tid=#{tid} #{format_context}: #{message}\n"
107
60
  end
108
61
  end
109
62
 
@@ -85,15 +85,15 @@ module Sidekiq
85
85
  end
86
86
 
87
87
  def fetch(conn, now = Time.now)
88
- window = now.utc.strftime("%d-%H:%-M")
89
- key = "#{@klass}-#{window}"
88
+ window = now.utc.strftime("%-d-%-H:%-M")
89
+ key = "h|#{@klass}-#{window}"
90
90
  conn.bitfield_ro(key, *FETCH)
91
91
  end
92
92
 
93
93
  def persist(conn, now = Time.now)
94
94
  buckets, @buckets = @buckets, []
95
- window = now.utc.strftime("%d-%H:%-M")
96
- key = "#{@klass}-#{window}"
95
+ window = now.utc.strftime("%-d-%-H:%-M")
96
+ key = "h|#{@klass}-#{window}"
97
97
  cmd = [key, "OVERFLOW", "SAT"]
98
98
  buckets.each_with_index do |counter, idx|
99
99
  val = counter.value
@@ -10,6 +10,8 @@ module Sidekiq
10
10
  def create(options = {})
11
11
  symbolized_options = deep_symbolize_keys(options)
12
12
  symbolized_options[:url] ||= determine_redis_provider
13
+ symbolized_options[:password] = wrap(symbolized_options[:password]) if symbolized_options.key?(:password)
14
+ symbolized_options[:sentinel_password] = wrap(symbolized_options[:sentinel_password]) if symbolized_options.key?(:sentinel_password)
13
15
 
14
16
  logger = symbolized_options.delete(:logger)
15
17
  logger&.info { "Sidekiq #{Sidekiq::VERSION} connecting to Redis with options #{scrub(symbolized_options)}" }
@@ -38,6 +40,15 @@ module Sidekiq
38
40
 
39
41
  private
40
42
 
43
+ # Wrap hard-coded passwords in a Proc to avoid logging the value
44
+ def wrap(pwd)
45
+ if pwd.is_a?(String)
46
+ ->(username) { pwd }
47
+ else
48
+ pwd
49
+ end
50
+ end
51
+
41
52
  def deep_symbolize_keys(object)
42
53
  case object
43
54
  when Hash
@@ -57,14 +68,14 @@ module Sidekiq
57
68
  # Deep clone so we can muck with these options all we want and exclude
58
69
  # params from dump-and-load that may contain objects that Marshal is
59
70
  # unable to safely dump.
60
- keys = options.keys - [:logger, :ssl_params]
71
+ keys = options.keys - [:logger, :ssl_params, :password, :sentinel_password]
61
72
  scrubbed_options = Marshal.load(Marshal.dump(options.slice(*keys)))
62
73
  if scrubbed_options[:url] && (uri = URI.parse(scrubbed_options[:url])) && uri.password
63
74
  uri.password = redacted
64
75
  scrubbed_options[:url] = uri.to_s
65
76
  end
66
- scrubbed_options[:password] = redacted if scrubbed_options[:password]
67
- scrubbed_options[:sentinel_password] = redacted if scrubbed_options[:sentinel_password]
77
+ scrubbed_options[:password] = redacted if options.key?(:password)
78
+ scrubbed_options[:sentinel_password] = redacted if options.key?(:sentinel_password)
68
79
  scrubbed_options[:sentinels]&.each do |sentinel|
69
80
  if sentinel.is_a?(String)
70
81
  if (uri = URI(sentinel)) && uri.password
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sidekiq
4
- VERSION = "8.0.0.beta2"
4
+ VERSION = "8.0.0"
5
5
  MAJOR = 8
6
6
 
7
7
  def self.gem_version
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "base64"
4
3
  require "sidekiq/paginator"
5
4
  require "sidekiq/web/helpers"
6
5
 
@@ -50,7 +49,7 @@ module Sidekiq
50
49
  end
51
50
 
52
51
  get "/" do
53
- @redis_info = redis_info.select { |k, v| REDIS_KEYS.include? k }
52
+ @redis_info = redis_info.slice(*REDIS_KEYS)
54
53
  days = (url_params("days") || 30).to_i
55
54
  return halt(401) if days < 1 || days > 180
56
55
 
@@ -327,7 +326,7 @@ module Sidekiq
327
326
 
328
327
  get "/stats" do
329
328
  sidekiq_stats = Sidekiq::Stats.new
330
- redis_stats = redis_info.select { |k, v| REDIS_KEYS.include? k }
329
+ redis_stats = redis_info.slice(*REDIS_KEYS)
331
330
  json(
332
331
  sidekiq: {
333
332
  processed: sidekiq_stats.processed,
@@ -368,7 +367,8 @@ module Sidekiq
368
367
  {"Accept" => "application/vnd.firefox-profiler+json;version=1.0",
369
368
  "User-Agent" => "Sidekiq #{Sidekiq::VERSION} job profiler"})
370
369
  # https://raw.githubusercontent.com/firefox-devtools/profiler-server/master/tools/decode_jwt_payload.py
371
- sid = Sidekiq.load_json(Base64.decode64(resp.body.split(".")[1]))["profileToken"]
370
+ rawjson = resp.body.split(".")[1].unpack1("m")
371
+ sid = Sidekiq.load_json(rawjson)["profileToken"]
372
372
  Sidekiq.redis { |c| c.hset(key, "sid", sid) }
373
373
  end
374
374
  url = config[:profile_view_url] % sid
@@ -14,7 +14,8 @@ module Sidekiq
14
14
  #
15
15
  # This should go in your `config/routes.rb` or similar. It
16
16
  # does not belong in your initializer since Web should not be
17
- # loaded in some processes (like an actual Sidekiq process)
17
+ # loaded in some processes (like an actual Sidekiq process).
18
+ # See `examples/webui-ext` for a sample web extension.
18
19
  class Config
19
20
  extend Forwardable
20
21
 
data/lib/sidekiq/web.rb CHANGED
@@ -63,8 +63,7 @@ module Sidekiq
63
63
  def use(*args, &block) = @@config.middlewares << [args, block]
64
64
 
65
65
  def register(*args, **kw, &block)
66
- # TODO
67
- puts "`Sidekiq::Web.register` is deprecated, use `Sidekiq::Web.configure {|cfg| cfg.register(...) }`"
66
+ Sidekiq.logger.warn { "`Sidekiq::Web.register` is deprecated, use `Sidekiq::Web.configure {|cfg| cfg.register(...) }`" }
68
67
  @@config.register(*args, **kw, &block)
69
68
  end
70
69
  end
data/sidekiq.gemspec CHANGED
@@ -27,6 +27,5 @@ Gem::Specification.new do |gem|
27
27
  gem.add_dependency "connection_pool", ">= 2.5.0"
28
28
  gem.add_dependency "rack", ">= 3.1.0"
29
29
  gem.add_dependency "json", ">= 2.9.0"
30
- gem.add_dependency "logger"
31
- gem.add_dependency "base64"
30
+ gem.add_dependency "logger", ">= 1.6.2"
32
31
  end
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.0.beta2
4
+ version: 8.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Perham
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-02-26 00:00:00.000000000 Z
10
+ date: 2025-03-05 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: redis-client
@@ -71,28 +71,14 @@ dependencies:
71
71
  requirements:
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
- version: '0'
74
+ version: 1.6.2
75
75
  type: :runtime
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - ">="
80
80
  - !ruby/object:Gem::Version
81
- version: '0'
82
- - !ruby/object:Gem::Dependency
83
- name: base64
84
- requirement: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - ">="
87
- - !ruby/object:Gem::Version
88
- version: '0'
89
- type: :runtime
90
- prerelease: false
91
- version_requirements: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - ">="
94
- - !ruby/object:Gem::Version
95
- version: '0'
81
+ version: 1.6.2
96
82
  description: Simple, efficient background processing for Ruby.
97
83
  email:
98
84
  - info@contribsys.com