Class: Wurk::Middleware::Chain
- Inherits:
-
Object
- Object
- Wurk::Middleware::Chain
- Includes:
- Enumerable
- Defined in:
- lib/wurk/middleware/chain.rb
Overview
Ordered list of middleware bound to a config/capsule. Sidekiq contract:
add appends (removing any existing entry for the same klass), prepend
pushes to index 0, insert_before/insert_after anchor relative to an
existing entry, invoke walks the chain handing the inner block to each.
Entries store klass + ctor args, not the live object: every job gets a
fresh instance per entry (invoke builds each as it reaches it, retrieve
builds them all up front). This keeps middleware thread-safe by
construction and matches Sidekiq's lifecycle.
Spec: docs/target/sidekiq-free.md §10.1.
Defined Under Namespace
Classes: Entry
Instance Attribute Summary collapse
-
#config ⇒ Object
Returns the value of attribute config.
-
#entries ⇒ Object
readonly
Returns the value of attribute entries.
Instance Method Summary collapse
- #add(klass) ⇒ Object
- #clear ⇒ Object
-
#copy_for(capsule) ⇒ Object
Bind a duplicate of this chain to
capsule. - #each ⇒ Object
- #empty? ⇒ Boolean
- #exists?(klass) ⇒ Boolean (also: #include?)
-
#initialize(config = nil) {|_self| ... } ⇒ Chain
constructor
A new instance of Chain.
- #insert_after(oldklass, newklass) ⇒ Object
- #insert_before(oldklass, newklass) ⇒ Object
-
#invoke(*args, &block) ⇒ Object
Walks the chain inside-out.
- #prepend(klass) ⇒ Object
- #remove(klass) ⇒ Object
- #retrieve ⇒ Object
Constructor Details
#initialize(config = nil) {|_self| ... } ⇒ Chain
Returns a new instance of Chain.
22 23 24 25 26 |
# File 'lib/wurk/middleware/chain.rb', line 22 def initialize(config = nil) @config = config @entries = [] yield self if block_given? end |
Instance Attribute Details
#config ⇒ Object
Returns the value of attribute config.
20 21 22 |
# File 'lib/wurk/middleware/chain.rb', line 20 def config @config end |
#entries ⇒ Object (readonly)
Returns the value of attribute entries.
19 20 21 |
# File 'lib/wurk/middleware/chain.rb', line 19 def entries @entries end |
Instance Method Details
#add(klass) ⇒ Object
43 44 45 46 |
# File 'lib/wurk/middleware/chain.rb', line 43 def add(klass, *) remove(klass) @entries << Entry.new(klass, *) end |
#clear ⇒ Object
80 81 82 |
# File 'lib/wurk/middleware/chain.rb', line 80 def clear @entries.clear end |
#copy_for(capsule) ⇒ Object
Bind a duplicate of this chain to capsule. Capsules share the parent
config's entries by reference initially but mutate independently after
the first add/remove/etc. (Array#dup on @entries).
33 34 35 36 37 |
# File 'lib/wurk/middleware/chain.rb', line 33 def copy_for(capsule) copy = dup copy.instance_variable_set(:@config, capsule) copy end |
#each ⇒ Object
28 |
# File 'lib/wurk/middleware/chain.rb', line 28 def each(&) = @entries.each(&) |
#empty? ⇒ Boolean
72 73 74 |
# File 'lib/wurk/middleware/chain.rb', line 72 def empty? @entries.empty? end |
#exists?(klass) ⇒ Boolean Also known as: include?
67 68 69 |
# File 'lib/wurk/middleware/chain.rb', line 67 def exists?(klass) any? { |entry| entry.klass == klass } end |
#insert_after(oldklass, newklass) ⇒ Object
60 61 62 63 64 65 |
# File 'lib/wurk/middleware/chain.rb', line 60 def insert_after(oldklass, newklass, *) i = @entries.index { |entry| entry.klass == newklass } new_entry = i.nil? ? Entry.new(newklass, *) : @entries.delete_at(i) i = @entries.index { |entry| entry.klass == oldklass } || (@entries.size - 1) @entries.insert(i + 1, new_entry) end |
#insert_before(oldklass, newklass) ⇒ Object
53 54 55 56 57 58 |
# File 'lib/wurk/middleware/chain.rb', line 53 def insert_before(oldklass, newklass, *) i = @entries.index { |entry| entry.klass == newklass } new_entry = i.nil? ? Entry.new(newklass, *) : @entries.delete_at(i) i = @entries.index { |entry| entry.klass == oldklass } || 0 @entries.insert(i, new_entry) end |
#invoke(*args, &block) ⇒ Object
Walks the chain inside-out. Each middleware receives a block that
advances to the next; the innermost block is the caller's &block,
whose return value is propagated back out. Empty chain: yield.
Hot path — one job pays this per invocation, so instantiation is folded
into an index walk over @entries: no instance array from retrieve,
no traversal lambda, and no shift (which memmoves the array per entry).
Cost is one allocation per entry (the middleware itself), zero to walk.
92 93 94 95 96 97 |
# File 'lib/wurk/middleware/chain.rb', line 92 def invoke(*args, &block) raise ArgumentError, 'middleware chain requires a block' unless block return yield if @entries.empty? traverse(@entries, 0, args, &block) end |
#prepend(klass) ⇒ Object
48 49 50 51 |
# File 'lib/wurk/middleware/chain.rb', line 48 def prepend(klass, *) remove(klass) @entries.unshift(Entry.new(klass, *)) end |
#remove(klass) ⇒ Object
39 40 41 |
# File 'lib/wurk/middleware/chain.rb', line 39 def remove(klass) @entries.delete_if { |entry| entry.klass == klass } end |
#retrieve ⇒ Object
76 77 78 |
# File 'lib/wurk/middleware/chain.rb', line 76 def retrieve map { |entry| entry.make_new(@config) } end |