# frozen_string_literal: true module SidekiqUniqueJobs module Script # Interface to dealing with .lua files # # @author Mikael Henriksson class Scripts # # @return [Concurrent::Map] a map with configured script paths SCRIPT_PATHS = Concurrent::Map.new # # Fetch a scripts configuration for path # # @param [Pathname] root_path the path to scripts # # @return [Scripts] a collection of scripts # def self.fetch(root_path) if (scripts = SCRIPT_PATHS.get(root_path)) return scripts end create(root_path) end # # Create a new scripts collection based on path # # @param [Pathname] root_path the path to scripts # # @return [Scripts] a collection of scripts # def self.create(root_path) scripts = new(root_path) store(scripts) end # # Store the scripts collection in memory # # @param [Scripts] scripts the path to scripts # # @return [Scripts] the scripts instance that was stored # def self.store(scripts) SCRIPT_PATHS.put(scripts.root_path, scripts) scripts end # # @!attribute [r] scripts # @return [Concurrent::Map] a collection of loaded scripts attr_reader :scripts # # @!attribute [r] root_path # @return [Pathname] the path to the directory with lua scripts attr_reader :root_path def initialize(path) raise ArgumentError, "path needs to be a Pathname" unless path.is_a?(Pathname) @scripts = Concurrent::Map.new @root_path = path end def fetch(name, conn) if (script = scripts.get(name.to_sym)) return script end load(name, conn) end def load(name, conn) script = Script.load(name, root_path, conn) scripts.put(name.to_sym, script) script end def delete(script) if script.is_a?(Script) scripts.delete(script.name) else scripts.delete(script.to_sym) end end def kill(conn) if conn.respond_to?(:namespace) conn.redis.script(:kill) else conn.script(:kill) end end # # Execute a lua script with given name # # @note this method is recursive if we need to load a lua script # that wasn't previously loaded. # # @param [Symbol] name the name of the script to execute # @param [Redis] conn the redis connection to use for execution # @param [Array] keys script keys # @param [Array] argv script arguments # # @return value from script # def execute(name, conn, keys: [], argv: []) script = fetch(name, conn) conn.evalsha(script.sha, keys, argv) end def count scripts.keys.size end end end end