Class: Karafka::Core::Configurable::Node

Inherits:
Object
  • Object
show all
Defined in:
lib/karafka/core/configurable/node.rb

Overview

Single non-leaf node This is a core component for the configurable settings

The idea here is simple: we collect settings (leafs) and children (nodes) information and we only compile/initialize the values prior to user running the ‘#configure` API. This API needs to run prior to using the result stuff even if there is nothing to configure

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(node_name, nestings = ->(_) {}, evaluate: true) ⇒ Node

Returns a new instance of Node.

Parameters:

  • node_name (Symbol)

    node name

  • nestings (Proc) (defaults to: ->(_) {})

    block for nested settings

  • evaluate (Boolean) (defaults to: true)

    when false, skip evaluating the nestings block. Used by deep_dup to avoid re-creating children that will be overwritten immediately.



22
23
24
25
26
27
28
29
30
# File 'lib/karafka/core/configurable/node.rb', line 22

def initialize(node_name, nestings = ->(_) {}, evaluate: true)
  @node_name = node_name
  @children = []
  @nestings = nestings
  @compiled = false
  @configs_refs = {}
  @local_defs = {}
  instance_eval(&nestings) if evaluate
end

Instance Attribute Details

#childrenObject

We need to be able to redefine children for deep copy



16
17
18
# File 'lib/karafka/core/configurable/node.rb', line 16

def children
  @children
end

#nestingsObject (readonly)

Returns the value of attribute nestings.



13
14
15
# File 'lib/karafka/core/configurable/node.rb', line 13

def nestings
  @nestings
end

#node_nameObject (readonly)

Returns the value of attribute node_name.



13
14
15
# File 'lib/karafka/core/configurable/node.rb', line 13

def node_name
  @node_name
end

Instance Method Details

#compileObject

Note:

It runs once, after things are compiled, they will not be recompiled again

Converts the settings definitions into end children



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/karafka/core/configurable/node.rb', line 133

def compile
  @children.each do |value|
    # Do not redefine something that was already set during compilation
    # This will allow us to reconfigure things and skip override with defaults
    skippable = @configs_refs.key?(value.node_name) || (value.is_a?(Leaf) && value.compiled?)
    lazy_leaf = value.is_a?(Leaf) && value.lazy?

    # Do not create accessor for leafs that are lazy as they will get a custom method
    # created instead
    build_accessors(value) unless lazy_leaf

    next if skippable

    initialized = if value.is_a?(Leaf)
      value.compiled = true

      if value.constructor && value.lazy?
        false
      elsif value.constructor
        call_constructor(value)
      else
        value.default
      end
    else
      value.compile
      value
    end

    if lazy_leaf && !initialized
      build_dynamic_accessor(value)
    else
      @configs_refs[value.node_name] = initialized
    end
  end

  @compiled = true
end

#configure {|_self| ... } ⇒ Node

Allows for the configuration and setup of the settings

Compile settings, allow for overrides via yielding

Yields:

  • (_self)

Yield Parameters:

Returns:

  • (Node)

    returns self after configuration



53
54
55
56
57
# File 'lib/karafka/core/configurable/node.rb', line 53

def configure
  compile if !@compiled || node_name == :root
  yield(self) if block_given?
  self
end

#deep_dupNode

Deep copies all the children nodes to allow us for templates building on a class level and non-side-effect usage on an instance/inherited.

Returns:

  • (Node)

    duplicated node



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/karafka/core/configurable/node.rb', line 87

def deep_dup
  dupped = Node.new(node_name, nestings, evaluate: false)

  children.each do |value|
    dupped.children << if value.is_a?(Leaf)
      # After inheritance we need to reload the state so the leafs are recompiled again
      value = value.dup
      value.compiled = false
      value
    else
      value.deep_dup
    end
  end

  dupped
end

#register(name, value) ⇒ Object

Registers a key-value pair as a setting on an already-compiled node without going through the static ‘setting` DSL. Useful for dynamic registries (e.g. named clusters) where the keys are not known at class-load time.

Unlike ‘setting`, which is designed to be called at class-definition time, `register` is safe to call at runtime because it:

- appends a pre-compiled Leaf so `deep_dup` and `to_h` include it
- sets `@configs_refs` directly so the reader accessor returns the value immediately
- builds reader/writer accessors via the same `build_accessors` path

Raises ‘ArgumentError` if the name is already registered to prevent silent overwrites.

Parameters:

  • name (Symbol, String)

    setting name

  • value (Object)

    the setting value assigned immediately; also used as the default when the node is deep-duped and recompiled on a new instance

Raises:

  • (ArgumentError)

    when the name is already taken



120
121
122
123
124
125
126
127
128
129
# File 'lib/karafka/core/configurable/node.rb', line 120

def register(name, value)
  name = name.to_sym

  raise ArgumentError, "#{name} is already registered" if @configs_refs.key?(name)

  leaf = Leaf.new(name, value, nil, true, false)
  @children << leaf
  build_accessors(leaf)
  @configs_refs[name] = value
end

#setting(node_name, default: nil, constructor: nil, lazy: false, &block) ⇒ Object

Allows for a single leaf or nested node definition

Parameters:

  • node_name (Symbol)

    setting or nested node name

  • default (Object) (defaults to: nil)

    default value

  • constructor (#call, nil) (defaults to: nil)

    callable or nil

  • lazy (Boolean) (defaults to: false)

    is this a lazy leaf

  • block (Proc)

    block for nested settings



39
40
41
42
43
44
45
46
47
# File 'lib/karafka/core/configurable/node.rb', line 39

def setting(node_name, default: nil, constructor: nil, lazy: false, &block)
  @children << if block
    Node.new(node_name, block)
  else
    Leaf.new(node_name, default, constructor, false, lazy)
  end

  compile
end

#to_hHash

Returns frozen config hash representation.

Returns:

  • (Hash)

    frozen config hash representation



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/karafka/core/configurable/node.rb', line 60

def to_h
  config = {}

  @children.each do |value|
    config[value.node_name] = if value.is_a?(Leaf)
      result = if @configs_refs.key?(value.node_name)
        @configs_refs[value.node_name]
      elsif value.constructor
        value.constructor.call
      elsif value.default
        value.default
      end

      # We need to check if value is not a result node for cases
      # where we merge additional config
      result.is_a?(Node) ? result.to_h : result
    else
      value.to_h
    end
  end

  config.freeze
end