Class: Errsight::Client
- Inherits:
-
Object
- Object
- Errsight::Client
- Defined in:
- lib/errsight/client.rb
Class Method Summary collapse
-
.cert_store ⇒ Object
Cached once at process boot — set_default_paths reads the system trust store from disk and is expensive to redo per request.
Instance Method Summary collapse
- #enqueue(event) ⇒ Object
- #flush! ⇒ Object
-
#initialize(config) ⇒ Client
constructor
A new instance of Client.
- #shutdown! ⇒ Object
Constructor Details
#initialize(config) ⇒ Client
Returns a new instance of Client.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/errsight/client.rb', line 8 def initialize(config) @config = config @queue = [] @mutex = Mutex.new @pid = Process.pid @shutdown = false # Mutex + CV used to interrupt the flush worker's between-tick wait # on shutdown. Plain Thread#wakeup has a lost-wakeup race: if # shutdown! fires before the thread has entered its first sleep, # wakeup is dropped and the thread sleeps the full flush_interval. # CV#wait + setting the flag inside the same lock has no such race. @sleep_mutex = Mutex.new @sleep_cv = ConditionVariable.new # When the API returns 429, we set this to a Time and skip sends in # flush! until it elapses. Replaces a per-call `sleep retry_after` # that used to park the flush thread for up to 60s, during which new # events spilled past max_queue_size and got silently dropped. @rate_limited_until = nil start_flush_worker end |
Class Method Details
.cert_store ⇒ Object
Cached once at process boot — set_default_paths reads the system trust store from disk and is expensive to redo per request.
168 169 170 |
# File 'lib/errsight/client.rb', line 168 def self.cert_store @cert_store ||= OpenSSL::X509::Store.new.tap(&:set_default_paths) end |
Instance Method Details
#enqueue(event) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/errsight/client.rb', line 29 def enqueue(event) # Fork-safety gate: see detect_fork! comment. Cheapest possible check # since enqueue is on the hot path of every captured event. detect_fork! if @pid != Process.pid @mutex.synchronize do if @queue.size >= @config.max_queue_size @config.logger&.warn("[Errsight] Queue full (#{@config.max_queue_size}), dropping event") return end @queue << event end end |
#flush! ⇒ Object
43 44 45 46 47 48 49 50 51 |
# File 'lib/errsight/client.rb', line 43 def flush! return if rate_limited? events = nil @mutex.synchronize do return if @queue.empty? events = @queue.slice!(0, @config.batch_size) end send_events(events) if events&.any? end |
#shutdown! ⇒ Object
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/errsight/client.rb', line 53 def shutdown! # Set the flag and signal under the same lock the flush worker uses # for its CV#wait. This atomically transfers the shutdown signal: # either the worker hasn't entered wait yet (and will see @shutdown # immediately) or it's in wait (and the broadcast unblocks it). @sleep_mutex.synchronize do @shutdown = true @sleep_cv.broadcast end thread = @flush_thread # Bound total shutdown time. If a flush is stuck on a hung HTTP # request, kill it rather than block the host's signal handling. thread&.join(@config.shutdown_timeout) thread&.kill if thread&.alive? # The thread does a final drain on graceful exit; do one here too in # case we had to kill it, or in case shutdown! was called when no # flush thread was alive. flush! rescue nil # Lazy init guard: @http_mutex may be nil if no request ever fired, # in which case the old code raised NoMethodError on shutdown. http_mutex.synchronize { @http&.finish if @http&.started? } rescue StandardError # best-effort end |