sidekiq-unique-jobs 8.0.5 → 8.0.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sidekiq-unique-jobs might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1573748a7de5be552d85b9e74143425fd99b2e85e4e6be1ccdbbd8ba9ecc0f37
4
- data.tar.gz: 520fe1d492c9e088df5b6dc138d8bc4024516486c216e8223fe0f55462cfe691
3
+ metadata.gz: 0f2baa17d73480d2a3af58b1202e5145935944abebfddbd94a199248df87e729
4
+ data.tar.gz: 11037fd5c6ed9a61452026541c874928ec0d465def211c7f34e91d7d1bb23bb2
5
5
  SHA512:
6
- metadata.gz: 23542e9860f30b16f14c1907790e1bd491e98524dad73b726b88592b8e0cbcf06fa4b535837fc534e4ccf4a80d619840bdf7ec01c3104e3053f1ec5661ea92d5
7
- data.tar.gz: d61c18630ab31064bac8ed9fad52fc84a08ad9bc384ac39d9ed8a44e6e4b741aafa0ebd2845a9f465da8e811e634dab0a8f92ee768c9bb19f9ba8cdb64b10190
6
+ metadata.gz: 927072c34b1b7131352dbfe5ccd269bace168d601977dfcb63199183033202b6ec04824612620375b336de9e06501a2b39237370357494af66a376385260faa3
7
+ data.tar.gz: cb615cce8db1b353f0b12790ee35019c709586f94b497d5543ef43a50a782b1e09c47371ddd28b810243b15e7d983030c5a56999ef7535745f4596890fc983dd
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## [v8.0.5](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v8.0.5) (2023-11-11)
4
+
5
+ [Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v8.0.4...v8.0.5)
6
+
7
+ **Merged pull requests:**
8
+
9
+ - Bump @babel/traverse from 7.22.8 to 7.23.3 in /myapp [\#819](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/819) ([dependabot[bot]](https://github.com/apps/dependabot))
10
+ - Bump postcss from 8.4.21 to 8.4.31 in /myapp [\#811](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/811) ([dependabot[bot]](https://github.com/apps/dependabot))
11
+ - fix: `while_executing` should not invoke conflict strategy when the job was successfully executed \[v8\] [\#810](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/810) ([cuzik](https://github.com/cuzik))
12
+ - Bump actions/checkout from 3 to 4 [\#808](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/808) ([dependabot[bot]](https://github.com/apps/dependabot))
13
+ - Bump semver from 6.3.0 to 6.3.1 in /myapp [\#798](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/798) ([dependabot[bot]](https://github.com/apps/dependabot))
14
+ - Because `replace` is a client strategy, it should only remove client locks aka queue locks. [\#778](https://github.com/mhenrixon/sidekiq-unique-jobs/pull/778) ([bigzed](https://github.com/bigzed))
15
+
3
16
  ## [v8.0.4](https://github.com/mhenrixon/sidekiq-unique-jobs/tree/v8.0.4) (2023-11-11)
4
17
 
5
18
  [Full Changelog](https://github.com/mhenrixon/sidekiq-unique-jobs/compare/v7.1.30...v8.0.4)
@@ -59,7 +59,7 @@ module SidekiqUniqueJobs
59
59
  # NOTE: When debugging, check the last item in the returned array.
60
60
  [
61
61
  total_size.to_i,
62
- result[0].to_i, # next_cursor
62
+ result[0].to_i, # next_cursor
63
63
  result[1].map { |entry| load_json(entry) }.select { |entry| entry.is_a?(Hash) },
64
64
  ]
65
65
  end
@@ -39,12 +39,13 @@ module SidekiqUniqueJobs
39
39
  self.task = test_task || default_task
40
40
 
41
41
  with_logging_context do
42
- register_reaper_process
43
- log_info("Starting Reaper")
42
+ if register_reaper_process
43
+ log_info("Starting Reaper")
44
44
 
45
- task.add_observer(Observer.new)
46
- task.execute
47
- task
45
+ task.add_observer(Observer.new)
46
+ task.execute
47
+ task
48
+ end
48
49
  end
49
50
  end
50
51
 
@@ -56,7 +56,7 @@ module SidekiqUniqueJobs
56
56
  def do_call(file_name, conn, keys, argv)
57
57
  argv = argv.dup.push(now_f, debug_lua, max_history, file_name, redis_version)
58
58
 
59
- Script.execute(file_name, conn, keys: keys, argv: normalize_argv(argv))
59
+ SidekiqUniqueJobs::Script.execute(file_name, conn, keys: keys, argv: normalize_argv(argv))
60
60
  end
61
61
 
62
62
  #
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ module Script
5
+ # Interface to dealing with .lua files
6
+ #
7
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
8
+ class Client
9
+ include SidekiqUniqueJobs::Script::Timing
10
+
11
+ #
12
+ # @!attribute [r] logger
13
+ # @return [Logger] an instance of a logger
14
+ attr_reader :logger
15
+ #
16
+ # @!attribute [r] file_name
17
+ # @return [String] The name of the file to execute
18
+ attr_reader :config
19
+ #
20
+ # @!attribute [r] scripts
21
+ # @return [Scripts] the collection with loaded scripts
22
+ attr_reader :scripts
23
+
24
+ def initialize(config)
25
+ @config = config
26
+ @logger = config.logger
27
+ @scripts = Scripts.fetch(config.scripts_path)
28
+ end
29
+
30
+ #
31
+ # Execute a lua script with the provided script_name
32
+ #
33
+ # @note this method is recursive if we need to load a lua script
34
+ # that wasn't previously loaded.
35
+ #
36
+ # @param [Symbol] script_name the name of the script to execute
37
+ # @param [Redis] conn the redis connection to use for execution
38
+ # @param [Array<String>] keys script keys
39
+ # @param [Array<Object>] argv script arguments
40
+ #
41
+ # @return value from script
42
+ #
43
+ def execute(script_name, conn, keys: [], argv: [])
44
+ result, elapsed = timed do
45
+ scripts.execute(script_name, conn, keys: keys, argv: argv)
46
+ end
47
+
48
+ logger.debug("Executed #{script_name}.lua in #{elapsed}ms")
49
+ result
50
+ rescue ::RedisClient::CommandError => ex
51
+ handle_error(script_name, conn, ex) do
52
+ execute(script_name, conn, keys: keys, argv: argv)
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ #
59
+ # Handle errors to allow retrying errors that need retrying
60
+ #
61
+ # @param [RedisClient::CommandError] ex exception to handle
62
+ #
63
+ # @return [void]
64
+ #
65
+ # @yieldreturn [void] yields back to the caller when NOSCRIPT is raised
66
+ def handle_error(script_name, conn, ex)
67
+ case ex.message
68
+ when /NOSCRIPT/
69
+ handle_noscript(script_name) { return yield }
70
+ when /BUSY/
71
+ handle_busy(conn) { return yield }
72
+ end
73
+
74
+ raise unless LuaError.intercepts?(ex)
75
+
76
+ script = scripts.fetch(script_name, conn)
77
+ raise LuaError.new(ex, script)
78
+ end
79
+
80
+ def handle_noscript(script_name)
81
+ scripts.delete(script_name)
82
+ yield
83
+ end
84
+
85
+ def handle_busy(conn)
86
+ scripts.kill(conn)
87
+ rescue ::RedisClient::CommandError => ex
88
+ logger.warn(ex)
89
+ ensure
90
+ yield
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ module Script
5
+ #
6
+ # Class holding gem configuration
7
+ #
8
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
9
+ class Config
10
+ #
11
+ # @!attribute [r] logger
12
+ # @return [Logger] a logger to use for debugging
13
+ attr_reader :logger
14
+ #
15
+ # @!attribute [r] scripts_path
16
+ # @return [Pathname] a directory with lua scripts
17
+ attr_reader :scripts_path
18
+
19
+ #
20
+ # Initialize a new instance of {Config}
21
+ #
22
+ #
23
+ def initialize
24
+ @conn = RedisClient.new
25
+ @logger = Logger.new($stdout)
26
+ @scripts_path = nil
27
+ end
28
+
29
+ #
30
+ # Sets a value for scripts_path
31
+ #
32
+ # @param [String, Pathname] obj <description>
33
+ #
34
+ # @raise [ArgumentError] when directory does not exist
35
+ # @raise [ArgumentError] when argument isn't supported
36
+ #
37
+ # @return [Pathname]
38
+ #
39
+ def scripts_path=(obj)
40
+ raise ArgumentError, "#{obj} should be a Pathname or String" unless obj.is_a?(Pathname) || obj.is_a?(String)
41
+ raise ArgumentError, "#{obj} does not exist" unless Dir.exist?(obj.to_s)
42
+
43
+ @scripts_path =
44
+ case obj
45
+ when String
46
+ Pathname.new(obj)
47
+ else
48
+ obj
49
+ end
50
+ end
51
+
52
+ #
53
+ # Sets a value for logger
54
+ #
55
+ # @param [Logger] obj a logger to use
56
+ #
57
+ # @raise [ArgumentError] when given argument isn't a Logger
58
+ #
59
+ # @return [Logger]
60
+ #
61
+ def logger=(obj)
62
+ raise ArgumentError, "#{obj} should be a Logger" unless obj.is_a?(Logger)
63
+
64
+ @logger = obj
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ module Script
5
+ # Interface to dealing with .lua files
6
+ #
7
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
8
+ module DSL
9
+ MUTEX = Mutex.new
10
+
11
+ def self.included(base)
12
+ base.class_eval do
13
+ extend ClassMethods
14
+ end
15
+ end
16
+
17
+ #
18
+ # Module ClassMethods extends the base class with necessary methods
19
+ #
20
+ # @author Mikael Henriksson <mikael@zoolutions.se>
21
+ #
22
+ module ClassMethods
23
+ def execute(file_name, conn, keys: [], argv: [])
24
+ SidekiqUniqueJobs::Script::Client
25
+ .new(config)
26
+ .execute(file_name, conn, keys: keys, argv: argv)
27
+ end
28
+
29
+ # Configure the gem
30
+ #
31
+ # This is usually called once at startup of an application
32
+ # @param [Hash] options global gem options
33
+ # @option options [String, Pathname] :path
34
+ # @option options [Logger] :logger (default is Logger.new(STDOUT))
35
+ # @yield control to the caller when given block
36
+ def configure(options = {})
37
+ if block_given?
38
+ yield config
39
+ else
40
+ options.each do |key, val|
41
+ config.send(:"#{key}=", val)
42
+ end
43
+ end
44
+ end
45
+
46
+ #
47
+ # The current configuration (See: {.configure} on how to configure)
48
+ #
49
+ #
50
+ # @return [Script::Config] the gem configuration
51
+ #
52
+ def config
53
+ MUTEX.synchronize do
54
+ @config ||= Config.new
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ module Script
5
+ # Utility module for reducing the number of uses of logger.
6
+ #
7
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
8
+ module Logging
9
+ def self.included(base)
10
+ base.send(:extend, self)
11
+ end
12
+
13
+ #
14
+ # A convenience method for using the configured gem logger
15
+ #
16
+ # @see Script#.logger
17
+ #
18
+ # @return [Logger]
19
+ #
20
+ def logger
21
+ SidekiqUniqueJobs::Script.logger
22
+ end
23
+
24
+ #
25
+ # Logs a message at debug level
26
+ #
27
+ # @param [String, Exception] message_or_exception the message or exception to log
28
+ #
29
+ # @return [void]
30
+ #
31
+ # @yield [String, Exception] the message or exception to use for log message
32
+ #
33
+ def log_debug(message_or_exception = nil, &block)
34
+ logger.debug(message_or_exception, &block)
35
+ nil
36
+ end
37
+
38
+ #
39
+ # Logs a message at info level
40
+ #
41
+ # @param [String, Exception] message_or_exception the message or exception to log
42
+ #
43
+ # @return [void]
44
+ #
45
+ # @yield [String, Exception] the message or exception to use for log message
46
+ #
47
+ def log_info(message_or_exception = nil, &block)
48
+ logger.info(message_or_exception, &block)
49
+ nil
50
+ end
51
+
52
+ #
53
+ # Logs a message at warn level
54
+ #
55
+ # @param [String, Exception] message_or_exception the message or exception to log
56
+ #
57
+ # @return [void]
58
+ #
59
+ # @yield [String, Exception] the message or exception to use for log message
60
+ #
61
+ def log_warn(message_or_exception = nil, &block)
62
+ logger.warn(message_or_exception, &block)
63
+ nil
64
+ end
65
+
66
+ #
67
+ # Logs a message at error level
68
+ #
69
+ # @param [String, Exception] message_or_exception the message or exception to log
70
+ #
71
+ # @return [void]
72
+ #
73
+ # @yield [String, Exception] the message or exception to use for log message
74
+ #
75
+ def log_error(message_or_exception = nil, &block)
76
+ logger.error(message_or_exception, &block)
77
+ nil
78
+ end
79
+
80
+ #
81
+ # Logs a message at fatal level
82
+ #
83
+ # @param [String, Exception] message_or_exception the message or exception to log
84
+ #
85
+ # @return [void]
86
+ #
87
+ # @yield [String, Exception] the message or exception to use for log message
88
+ #
89
+ def log_fatal(message_or_exception = nil, &block)
90
+ logger.fatal(message_or_exception, &block)
91
+ nil
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ module Script
5
+ #
6
+ # Misconfiguration is raised when gem is misconfigured
7
+ #
8
+ # @author Mikael Henriksson <mikael@zoolutions.se>
9
+ #
10
+ class Misconfiguration < RuntimeError
11
+ end
12
+
13
+ # LuaError raised on errors in Lua scripts
14
+ #
15
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
16
+ class LuaError < RuntimeError
17
+ # Reformats errors raised by redis representing failures while executing
18
+ # a lua script. The default errors have confusing messages and backtraces,
19
+ # and a type of +RuntimeError+. This class improves the message and
20
+ # modifies the backtrace to include the lua script itself in a reasonable
21
+ # way.
22
+
23
+ PATTERN = /ERR Error (compiling|running) script \(.*?\): .*?:(\d+): (.*)/.freeze
24
+ LIB_PATH = File.expand_path("..", __dir__).freeze
25
+ CONTEXT_LINE_NUMBER = 2
26
+
27
+ attr_reader :error, :file, :content
28
+
29
+ # Is this error one that should be reformatted?
30
+ #
31
+ # @param error [StandardError] the original error raised by redis
32
+ # @return [Boolean] is this an error that should be reformatted?
33
+ def self.intercepts?(error)
34
+ PATTERN.match?(error.message)
35
+ end
36
+
37
+ # Initialize a new {LuaError} from an existing redis error, adjusting
38
+ # the message and backtrace in the process.
39
+ #
40
+ # @param error [StandardError] the original error raised by redis
41
+ # @param script [Script] a DTO with information about the script
42
+ #
43
+ def initialize(error, script)
44
+ @error = error
45
+ @file = script.path
46
+ @content = script.source
47
+ @backtrace = @error.backtrace
48
+
49
+ @error.message.match(PATTERN) do |regexp_match|
50
+ line_number = regexp_match[2].to_i
51
+ message = regexp_match[3]
52
+ error_context = generate_error_context(content, line_number)
53
+
54
+ super("#{message}\n\n#{error_context}\n\n")
55
+ set_backtrace(generate_backtrace(file, line_number))
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ # :nocov:
62
+ def generate_error_context(content, line_number)
63
+ lines = content.lines.to_a
64
+ beginning_line_number = [1, line_number - CONTEXT_LINE_NUMBER].max
65
+ ending_line_number = [lines.count, line_number + CONTEXT_LINE_NUMBER].min
66
+ line_number_width = ending_line_number.to_s.length
67
+
68
+ (beginning_line_number..ending_line_number).map do |number|
69
+ indicator = (number == line_number) ? "=>" : " "
70
+ formatted_number = format("%#{line_number_width}d", number)
71
+ " #{indicator} #{formatted_number}: #{lines[number - 1]}"
72
+ end.join.chomp
73
+ end
74
+
75
+ # :nocov:
76
+ def generate_backtrace(file, line_number)
77
+ pre_gem = backtrace_before_entering_gem(@backtrace)
78
+ index_of_first_gem_line = (@backtrace.size - pre_gem.size - 1)
79
+
80
+ pre_gem.unshift(@backtrace[index_of_first_gem_line])
81
+ pre_gem.unshift("#{file}:#{line_number}")
82
+ pre_gem
83
+ end
84
+
85
+ # :nocov:
86
+ def backtrace_before_entering_gem(backtrace)
87
+ backtrace.reverse.take_while { |line| !line_from_gem(line) }.reverse
88
+ end
89
+
90
+ # :nocov:
91
+ def line_from_gem(line)
92
+ line.split(":").first.include?(LIB_PATH)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ module Script
5
+ # Interface to dealing with .lua files
6
+ #
7
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
8
+ class Script
9
+ def self.load(name, root_path, conn)
10
+ script = new(name: name, root_path: root_path)
11
+ script.load(conn)
12
+ end
13
+
14
+ #
15
+ # @!attribute [r] script_name
16
+ # @return [Symbol, String] the name of the script without extension
17
+ attr_reader :name
18
+ #
19
+ # @!attribute [r] script_path
20
+ # @return [String] the path to the script on disk
21
+ attr_reader :path
22
+ #
23
+ # @!attribute [r] root_path
24
+ # @return [Pathname]
25
+ attr_reader :root_path
26
+ #
27
+ # @!attribute [r] source
28
+ # @return [String] the source code of the lua script
29
+ attr_reader :source
30
+ #
31
+ # @!attribute [rw] sha
32
+ # @return [String] the sha of the script
33
+ attr_reader :sha
34
+ #
35
+ # @!attribute [rw] call_count
36
+ # @return [Integer] the number of times the script was called/executed
37
+ attr_reader :call_count
38
+
39
+ def initialize(name:, root_path:)
40
+ @name = name
41
+ @root_path = root_path
42
+ @path = root_path.join("#{name}.lua").to_s
43
+ @source = render_file
44
+ @sha = compiled_sha
45
+ @call_count = 0
46
+ end
47
+
48
+ def ==(other)
49
+ sha == compiled_sha && compiled_sha == other.sha
50
+ end
51
+
52
+ def increment_call_count
53
+ @call_count += 1
54
+ end
55
+
56
+ def changed?
57
+ compiled_sha != sha
58
+ end
59
+
60
+ def render_file
61
+ Template.new(root_path).render(path)
62
+ end
63
+
64
+ def compiled_sha
65
+ Digest::SHA1.hexdigest(source)
66
+ end
67
+
68
+ def load(conn)
69
+ @sha =
70
+ if conn.respond_to?(:namespace)
71
+ conn.redis.script(:load, source)
72
+ else
73
+ conn.script(:load, source)
74
+ end
75
+
76
+ self
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ module Script
5
+ # Interface to dealing with .lua files
6
+ #
7
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
8
+ class Scripts
9
+ #
10
+ # @return [Concurrent::Map] a map with configured script paths
11
+ SCRIPT_PATHS = Concurrent::Map.new
12
+
13
+ #
14
+ # Fetch a scripts configuration for path
15
+ #
16
+ # @param [Pathname] root_path the path to scripts
17
+ #
18
+ # @return [Scripts] a collection of scripts
19
+ #
20
+ def self.fetch(root_path)
21
+ if (scripts = SCRIPT_PATHS.get(root_path))
22
+ return scripts
23
+ end
24
+
25
+ create(root_path)
26
+ end
27
+
28
+ #
29
+ # Create a new scripts collection based on path
30
+ #
31
+ # @param [Pathname] root_path the path to scripts
32
+ #
33
+ # @return [Scripts] a collection of scripts
34
+ #
35
+ def self.create(root_path)
36
+ scripts = new(root_path)
37
+ store(scripts)
38
+ end
39
+
40
+ #
41
+ # Store the scripts collection in memory
42
+ #
43
+ # @param [Scripts] scripts the path to scripts
44
+ #
45
+ # @return [Scripts] the scripts instance that was stored
46
+ #
47
+ def self.store(scripts)
48
+ SCRIPT_PATHS.put(scripts.root_path, scripts)
49
+ scripts
50
+ end
51
+
52
+ #
53
+ # @!attribute [r] scripts
54
+ # @return [Concurrent::Map] a collection of loaded scripts
55
+ attr_reader :scripts
56
+
57
+ #
58
+ # @!attribute [r] root_path
59
+ # @return [Pathname] the path to the directory with lua scripts
60
+ attr_reader :root_path
61
+
62
+ def initialize(path)
63
+ raise ArgumentError, "path needs to be a Pathname" unless path.is_a?(Pathname)
64
+
65
+ @scripts = Concurrent::Map.new
66
+ @root_path = path
67
+ end
68
+
69
+ def fetch(name, conn)
70
+ if (script = scripts.get(name.to_sym))
71
+ return script
72
+ end
73
+
74
+ load(name, conn)
75
+ end
76
+
77
+ def load(name, conn)
78
+ script = Script.load(name, root_path, conn)
79
+ scripts.put(name.to_sym, script)
80
+
81
+ script
82
+ end
83
+
84
+ def delete(script)
85
+ if script.is_a?(Script)
86
+ scripts.delete(script.name)
87
+ else
88
+ scripts.delete(script.to_sym)
89
+ end
90
+ end
91
+
92
+ def kill(conn)
93
+ if conn.respond_to?(:namespace)
94
+ conn.redis.script(:kill)
95
+ else
96
+ conn.script(:kill)
97
+ end
98
+ end
99
+
100
+ #
101
+ # Execute a lua script with given name
102
+ #
103
+ # @note this method is recursive if we need to load a lua script
104
+ # that wasn't previously loaded.
105
+ #
106
+ # @param [Symbol] name the name of the script to execute
107
+ # @param [Redis] conn the redis connection to use for execution
108
+ # @param [Array<String>] keys script keys
109
+ # @param [Array<Object>] argv script arguments
110
+ #
111
+ # @return value from script
112
+ #
113
+ def execute(name, conn, keys: [], argv: [])
114
+ script = fetch(name, conn)
115
+ conn.evalsha(script.sha, keys, argv)
116
+ end
117
+
118
+ def count
119
+ scripts.keys.size
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ # Interface to dealing with .lua files
5
+ #
6
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
7
+ module Script
8
+ #
9
+ # Class Template provides LUA script partial template rendering
10
+ #
11
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
12
+ #
13
+ class Template
14
+ def initialize(script_path)
15
+ @script_path = script_path
16
+ end
17
+
18
+ #
19
+ # Renders a Lua script and includes any partials in that file
20
+ # all `<%= include_partial '' %>` replaced with the actual contents of the partial
21
+ #
22
+ # @param [Pathname] pathname the path to the
23
+ #
24
+ # @return [String] the rendered Luascript
25
+ #
26
+ def render(pathname)
27
+ @partial_templates ||= {}
28
+ ::ERB.new(File.read(pathname)).result(binding)
29
+ end
30
+
31
+ # helper method to include a lua partial within another lua script
32
+ #
33
+ def include_partial(relative_path)
34
+ return if @partial_templates.key?(relative_path)
35
+
36
+ @partial_templates[relative_path] = nil
37
+ render(Pathname.new("#{@script_path}/#{relative_path}"))
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SidekiqUniqueJobs
4
+ module Script
5
+ # Handles timing> of things
6
+ #
7
+ # @author Mikael Henriksson <mikael@mhenrixon.com>
8
+ module Timing
9
+ module_function
10
+
11
+ #
12
+ # Used for timing method calls
13
+ #
14
+ #
15
+ # @return [yield return, Float]
16
+ #
17
+ def timed
18
+ start_time = now
19
+
20
+ [yield, now - start_time]
21
+ end
22
+
23
+ #
24
+ # Returns a float representation of the current time.
25
+ # Either from Process or Time
26
+ #
27
+ #
28
+ # @return [Float]
29
+ #
30
+ def now
31
+ (Process.clock_gettime(Process::CLOCK_MONOTONIC) * 1000).to_i
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,15 +1,46 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "sidekiq_unique_jobs/script/template"
4
+ require "sidekiq_unique_jobs/script/lua_error"
5
+ require "sidekiq_unique_jobs/script/script"
6
+ require "sidekiq_unique_jobs/script/scripts"
7
+ require "sidekiq_unique_jobs/script/config"
8
+ require "sidekiq_unique_jobs/script/timing"
9
+ require "sidekiq_unique_jobs/script/logging"
10
+ require "sidekiq_unique_jobs/script/dsl"
11
+ require "sidekiq_unique_jobs/script/client"
12
+
3
13
  module SidekiqUniqueJobs
4
14
  # Interface to dealing with .lua files
5
15
  #
6
16
  # @author Mikael Henriksson <mikael@mhenrixon.com>
7
17
  module Script
8
- include Brpoplpush::RedisScript::DSL
18
+ include SidekiqUniqueJobs::Script::DSL
9
19
 
10
20
  configure do |config|
11
21
  config.scripts_path = Pathname.new(__FILE__).dirname.join("lua")
12
22
  config.logger = Sidekiq.logger # TODO: This becomes a little weird
13
23
  end
24
+
25
+ #
26
+ # The current logger
27
+ #
28
+ #
29
+ # @return [Logger] the configured logger
30
+ #
31
+ def self.logger
32
+ config.logger
33
+ end
34
+
35
+ #
36
+ # Set a new logger
37
+ #
38
+ # @param [Logger] other another logger
39
+ #
40
+ # @return [Logger] the new logger
41
+ #
42
+ def self.logger=(other)
43
+ config.logger = other
44
+ end
14
45
  end
15
46
  end
@@ -186,7 +186,7 @@ module SidekiqUniqueJobs # rubocop:disable Metrics/ModuleLength
186
186
  yield config
187
187
  else
188
188
  options.each do |key, val|
189
- config.send("#{key}=", val)
189
+ config.send(:"#{key}=", val)
190
190
  end
191
191
  end
192
192
  end
@@ -3,5 +3,5 @@
3
3
  module SidekiqUniqueJobs
4
4
  #
5
5
  # @return [String] the current SidekiqUniqueJobs version
6
- VERSION = "8.0.5"
6
+ VERSION = "8.0.6"
7
7
  end
@@ -1,20 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "brpoplpush/redis_script"
3
+ require "concurrent/executor/ruby_single_thread_executor"
4
4
  require "concurrent/future"
5
- require "concurrent/promises"
6
5
  require "concurrent/map"
7
6
  require "concurrent/mutable_struct"
7
+ require "concurrent/promises"
8
8
  require "concurrent/timer_task"
9
- require "concurrent/executor/ruby_single_thread_executor"
10
9
  require "digest"
11
10
  require "digest/sha1"
12
11
  require "erb"
13
12
  require "forwardable"
14
13
  require "json"
15
14
  require "pathname"
15
+ require "redis_client"
16
16
  require "sidekiq"
17
17
 
18
+ require "sidekiq_unique_jobs/script"
19
+
18
20
  require "sidekiq_unique_jobs/deprecation"
19
21
  require "sidekiq_unique_jobs/reflections"
20
22
  require "sidekiq_unique_jobs/reflectable"
@@ -29,7 +31,6 @@ require "sidekiq_unique_jobs/timing"
29
31
  require "sidekiq_unique_jobs/sidekiq_worker_methods"
30
32
  require "sidekiq_unique_jobs/connection"
31
33
  require "sidekiq_unique_jobs/exceptions"
32
- require "sidekiq_unique_jobs/script"
33
34
  require "sidekiq_unique_jobs/script/caller"
34
35
  require "sidekiq_unique_jobs/normalizer"
35
36
  require "sidekiq_unique_jobs/job"
metadata CHANGED
@@ -1,35 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-unique-jobs
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.5
4
+ version: 8.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikael Henriksson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-11 00:00:00.000000000 Z
11
+ date: 2024-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: brpoplpush-redis_script
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">"
18
- - !ruby/object:Gem::Version
19
- version: 0.1.1
20
- - - "<="
21
- - !ruby/object:Gem::Version
22
- version: 2.0.0
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - ">"
28
- - !ruby/object:Gem::Version
29
- version: 0.1.1
30
- - - "<="
31
- - !ruby/object:Gem::Version
32
- version: 2.0.0
33
13
  - !ruby/object:Gem::Dependency
34
14
  name: concurrent-ruby
35
15
  requirement: !ruby/object:Gem::Requirement
@@ -195,6 +175,15 @@ files:
195
175
  - lib/sidekiq_unique_jobs/rspec/matchers/have_valid_sidekiq_options.rb
196
176
  - lib/sidekiq_unique_jobs/script.rb
197
177
  - lib/sidekiq_unique_jobs/script/caller.rb
178
+ - lib/sidekiq_unique_jobs/script/client.rb
179
+ - lib/sidekiq_unique_jobs/script/config.rb
180
+ - lib/sidekiq_unique_jobs/script/dsl.rb
181
+ - lib/sidekiq_unique_jobs/script/logging.rb
182
+ - lib/sidekiq_unique_jobs/script/lua_error.rb
183
+ - lib/sidekiq_unique_jobs/script/script.rb
184
+ - lib/sidekiq_unique_jobs/script/scripts.rb
185
+ - lib/sidekiq_unique_jobs/script/template.rb
186
+ - lib/sidekiq_unique_jobs/script/timing.rb
198
187
  - lib/sidekiq_unique_jobs/server.rb
199
188
  - lib/sidekiq_unique_jobs/sidekiq_unique_ext.rb
200
189
  - lib/sidekiq_unique_jobs/sidekiq_unique_jobs.rb
@@ -234,7 +223,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
234
223
  - !ruby/object:Gem::Version
235
224
  version: '0'
236
225
  requirements: []
237
- rubygems_version: 3.4.20
226
+ rubygems_version: 3.5.5
238
227
  signing_key:
239
228
  specification_version: 4
240
229
  summary: Sidekiq middleware that prevents duplicates jobs