Class: Stoplight::Wiring::System Private

Inherits:
Object
  • Object
show all
Defined in:
lib/stoplight/wiring/system.rb,
lib/stoplight/wiring/system/light_builder.rb,
lib/stoplight/wiring/system/light_factory.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Note:

System configuration objects (data_store, notifiers) should be defined as constants and reused, not created inline. This ensures configuration matching works correctly across multiple system references.

Note:

Light instances are cached within the system. Calling #light with the same name returns the cached instance.

🚧UNDER CONSTRUCTION 🚧System provides namespace isolation and shared configuration for related circuits.

Systems enforce configuration consistency within their scope - creating the same circuit name with different settings raises Stoplight::Error::ConfigurationError.

This prevents subtle bugs where circuits silently interfere with each other.

Examples:

Basic usage

billing = Stoplight.system(:billing,
  data_store: billing_redis,
  threshold: 5,
  window_size: 300
)

billing.light("stripe")
billing.light("paypal")

Multi-tenancy

tenant_a = Stoplight.system(:tenant_a, data_store: tenant_a_redis)
tenant_b = Stoplight.system(:tenant_b, data_store: tenant_b_redis)

# Same circuit name, completely isolated
tenant_a.light("api")
tenant_b.light("api")

Configuration inheritance

system = Stoplight.system(:payments, threshold: 3, cool_off_time: 600)

system.light("stripe")                # Inherits threshold: 3
system.light("paypal", threshold: 5)  # Overrides threshold

Defined Under Namespace

Classes: LightBuilder, LightFactory

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config:) ⇒ System

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of System.



53
54
55
56
57
# File 'lib/stoplight/wiring/system.rb', line 53

def initialize(config:)
  @name = config.name
  @system_config = config
  @lights = Concurrent::Map.new
end

Instance Attribute Details

#nameObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



48
49
50
# File 'lib/stoplight/wiring/system.rb', line 48

def name
  @name
end

#system_configObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



51
52
53
# File 'lib/stoplight/wiring/system.rb', line 51

def system_config
  @system_config
end

Instance Method Details

#light(name, cool_off_time: T.undefined, threshold: T.undefined, recovery_threshold: T.undefined, window_size: T.undefined, tracked_errors: T.undefined, skipped_errors: T.undefined, traffic_control: T.undefined, traffic_recovery: T.undefined) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Note:

Thread-safe: multiple threads can safely call this method concurrently

Creates or retrieves a light.

If a light with this name already exists, returns the cached instance. If settings differ from the existing light, raises Stoplight::Error::ConfigurationError.

Examples:

Create a light

light = system.light("stripe", threshold: 5, window_size: 60)

Retrieve existing light - both return cached light

light = system.light("stripe", threshold: 5, window_size: 60)
light = system.light("stripe")

Configuration conflict

system.light("api", threshold: 5)
system.light("api", threshold: 10)  # Raises ConfigurationError

Raises:



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/stoplight/wiring/system.rb', line 80

def light(
  name,
  cool_off_time: T.undefined,
  threshold: T.undefined,
  recovery_threshold: T.undefined,
  window_size: T.undefined,
  tracked_errors: T.undefined,
  skipped_errors: T.undefined,
  traffic_control: T.undefined,
  traffic_recovery: T.undefined
)
  light_config = ConfigurationDsl.new(
    name:,
    cool_off_time:,
    threshold:,
    recovery_threshold:,
    window_size:,
    tracked_errors:,
    skipped_errors:,
    traffic_control:,
    traffic_recovery:
  ).configure!(system_config)

  light, _ = lights.compute(name) do |existing|
    if existing
      existing_light, existing_config = existing
      if light_config == existing_config
        [existing_light, existing_config]
      else
        raise Stoplight::Error::ConfigurationError, <<~MSG
          Light name `#{name}` reused with different settings:
            existing settings: #{existing_config}
            new settings:      #{light_config}

          You cannot use the same light name with different settings.
        MSG
      end
    else
      [LightFactory.new(system: self, config: light_config).build, light_config]
    end
  end
  light
end