Class: Shoryuken::Middleware::Chain

Inherits:
Object
  • Object
show all
Defined in:
lib/shoryuken/middleware/chain.rb

Overview

Manages a chain of middleware classes that will be instantiated and invoked in sequence around message processing. Provides methods for adding, removing, and reordering middleware.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize {|Chain| ... } ⇒ Chain

Creates a new middleware chain.

Examples:

Creating and configuring a chain

chain = Shoryuken::Middleware::Chain.new do |c|
  c.add MyMiddleware
  c.add AnotherMiddleware, option: 'value'
end

Yields:

  • (Chain)

    The chain instance for configuration



102
103
104
105
# File 'lib/shoryuken/middleware/chain.rb', line 102

def initialize
  @entries = []
  yield self if block_given?
end

Instance Attribute Details

#entriesArray<Entry> (readonly)

Returns The ordered list of middleware entries.

Returns:

  • (Array<Entry>)

    The ordered list of middleware entries



92
93
94
# File 'lib/shoryuken/middleware/chain.rb', line 92

def entries
  @entries
end

Instance Method Details

#add(klass, *args) ⇒ Object

Adds middleware to the end of the chain. Does nothing if the middleware class is already present in the chain.

Examples:

Adding middleware with arguments

chain.add MyMiddleware, timeout: 30, retries: 3

Parameters:

  • klass (Class)

    The middleware class to add

  • args (Array)

    Arguments to pass to the middleware constructor



131
132
133
# File 'lib/shoryuken/middleware/chain.rb', line 131

def add(klass, *args)
  entries << Entry.new(klass, *args) unless exists?(klass)
end

#clearArray

Removes all middleware from the chain.

Returns:

  • (Array)

    Empty array



194
195
196
# File 'lib/shoryuken/middleware/chain.rb', line 194

def clear
  entries.clear
end

#dupChain

Creates a copy of this middleware chain.

Returns:

  • (Chain)

    A new chain with the same middleware entries



110
111
112
# File 'lib/shoryuken/middleware/chain.rb', line 110

def dup
  self.class.new.tap { |new_chain| new_chain.entries.replace(entries) }
end

#exists?(klass) ⇒ Boolean

Checks if a middleware class is already in the chain.

Parameters:

  • klass (Class)

    The middleware class to check for

Returns:

  • (Boolean)

    True if the middleware is in the chain



180
181
182
# File 'lib/shoryuken/middleware/chain.rb', line 180

def exists?(klass)
  entries.any? { |entry| entry.klass == klass }
end

#insert_after(oldklass, newklass, *args) ⇒ Object

Inserts middleware immediately after another middleware class. If the new middleware already exists, it’s moved to the new position.

Examples:

Insert metrics collection after timing middleware

chain.insert_after Shoryuken::Middleware::Server::Timing, MetricsCollector

Parameters:

  • oldklass (Class)

    The existing middleware to insert after

  • newklass (Class)

    The middleware class to insert

  • args (Array)

    Arguments to pass to the middleware constructor



169
170
171
172
173
174
# File 'lib/shoryuken/middleware/chain.rb', line 169

def insert_after(oldklass, newklass, *args)
  i = entries.index { |entry| entry.klass == newklass }
  new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
  i = entries.find_index { |entry| entry.klass == oldklass } || entries.count - 1
  entries.insert(i + 1, new_entry)
end

#insert_before(oldklass, newklass, *args) ⇒ Object

Inserts middleware immediately before another middleware class. If the new middleware already exists, it’s moved to the new position.

Examples:

Insert database setup before ActiveRecord middleware

chain.insert_before Shoryuken::Middleware::Server::ActiveRecord, DatabaseSetup

Parameters:

  • oldklass (Class)

    The existing middleware to insert before

  • newklass (Class)

    The middleware class to insert

  • args (Array)

    Arguments to pass to the middleware constructor



154
155
156
157
158
159
# File 'lib/shoryuken/middleware/chain.rb', line 154

def insert_before(oldklass, newklass, *args)
  i = entries.index { |entry| entry.klass == newklass }
  new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
  i = entries.find_index { |entry| entry.klass == oldklass } || 0
  entries.insert(i, new_entry)
end

#invoke(*args) { ... } ⇒ Object

Invokes the middleware chain with the given arguments. Each middleware’s call method will be invoked in sequence, with control passed through yielding.

Parameters:

  • args (Array)

    Arguments to pass to each middleware

Yields:

  • The final action to perform after all middleware



204
205
206
207
208
209
210
211
212
213
214
# File 'lib/shoryuken/middleware/chain.rb', line 204

def invoke(*args, &final_action)
  chain = retrieve.dup
  traverse_chain = lambda do
    if chain.empty?
      final_action.call
    else
      chain.shift.call(*args, &traverse_chain)
    end
  end
  traverse_chain.call
end

#prepend(klass, *args) ⇒ Object

Adds middleware to the beginning of the chain. Does nothing if the middleware class is already present in the chain.

Examples:

Adding middleware to run first

chain.prepend AuthenticationMiddleware

Parameters:

  • klass (Class)

    The middleware class to prepend

  • args (Array)

    Arguments to pass to the middleware constructor



142
143
144
# File 'lib/shoryuken/middleware/chain.rb', line 142

def prepend(klass, *args)
  entries.insert(0, Entry.new(klass, *args)) unless exists?(klass)
end

#remove(klass) ⇒ Array<Entry>

Removes all instances of the specified middleware class from the chain.

Examples:

Removing ActiveRecord middleware

chain.remove Shoryuken::Middleware::Server::ActiveRecord

Parameters:

  • klass (Class)

    The middleware class to remove

Returns:

  • (Array<Entry>)

    The removed entries



120
121
122
# File 'lib/shoryuken/middleware/chain.rb', line 120

def remove(klass)
  entries.delete_if { |entry| entry.klass == klass }
end

#retrieveArray

Creates instances of all middleware classes in the chain.

Returns:

  • (Array)

    Array of middleware instances



187
188
189
# File 'lib/shoryuken/middleware/chain.rb', line 187

def retrieve
  entries.map(&:make_new)
end