Class: Apartment::TenantValidator
- Inherits:
-
Object
- Object
- Apartment::TenantValidator
- Defined in:
- lib/apartment/tenant_validator.rb
Overview
In-process, memoized validator: answers “is this a real tenant name?”. The positive set is sourced from config.tenants_provider, refreshed on a TTL and — rate-limited, single-flight — on a miss. Lifecycle notifications (create.apartment / drop.apartment) keep the set current between rebuilds; a tenants_provider error makes the validator fail open (allow all names).
Constant Summary collapse
- DEFAULT_POSITIVE_TTL_SECONDS =
300- DEFAULT_REBUILD_INTERVAL_SECONDS =
5
Instance Method Summary collapse
-
#call(name) ⇒ Boolean
(also: #valid?)
Whether ‘name` is a known tenant.
-
#evict(name) ⇒ Object
Remove a name from the positive set immediately.
-
#initialize(positive_ttl: DEFAULT_POSITIVE_TTL_SECONDS, rebuild_interval: DEFAULT_REBUILD_INTERVAL_SECONDS) ⇒ TenantValidator
constructor
A new instance of TenantValidator.
-
#shutdown ⇒ Object
Remove the ActiveSupport::Notifications subscriptions.
Constructor Details
#initialize(positive_ttl: DEFAULT_POSITIVE_TTL_SECONDS, rebuild_interval: DEFAULT_REBUILD_INTERVAL_SECONDS) ⇒ TenantValidator
Returns a new instance of TenantValidator.
16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/apartment/tenant_validator.rb', line 16 def initialize(positive_ttl: DEFAULT_POSITIVE_TTL_SECONDS, rebuild_interval: DEFAULT_REBUILD_INTERVAL_SECONDS) @positive_ttl = positive_ttl @rebuild_interval = rebuild_interval @names = Concurrent::Set.new @rebuild_mutex = Mutex.new # single-flight guard: one rebuild at a time @state_mutex = Mutex.new # guards the @names swap vs lifecycle deltas @pending_deltas = nil # non-nil Array while a rebuild is in flight @built_at = nil @last_rebuild_at = nil @degraded = false @subscribers = subscribe_to_lifecycle end |
Instance Method Details
#call(name) ⇒ Boolean Also known as: valid?
Returns whether ‘name` is a known tenant.
39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/apartment/tenant_validator.rb', line 39 def call(name) name = name.to_s if @built_at.nil? rebuild(blocking: true) # cold start: every caller waits for the first build elsif stale? rebuild # refresh: single-flight, non-blocking end return true if @degraded return true if @names.include?(name) rebuild_on_miss @degraded || @names.include?(name) end |
#evict(name) ⇒ Object
Remove a name from the positive set immediately. The request-path fail-safe (the elevator’s missing-tenant rescue) calls this when a switch hits a container that no longer exists, so this process stops validating a tenant dropped by another process before its TTL would otherwise heal it. Mid-rebuild evictions are captured as deltas and re-applied after the swap, mirroring drop.apartment handling, so the rebuild cannot resurrect the name.
60 61 62 |
# File 'lib/apartment/tenant_validator.rb', line 60 def evict(name) apply_lifecycle(:remove, name) end |
#shutdown ⇒ Object
Remove the ActiveSupport::Notifications subscriptions. Call when discarding a validator (Apartment.clear_config) so subscriptions do not accumulate across a process’s lifetime.
33 34 35 36 |
# File 'lib/apartment/tenant_validator.rb', line 33 def shutdown @subscribers.each { |s| ActiveSupport::Notifications.unsubscribe(s) } @subscribers = [] end |