Class: Beacon::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/beacon/client.rb

Overview

The top-level client. Owns the queue and the flusher, exposes track, implements fork safety. Beacon.track / Beacon.flush / Beacon.shutdown all delegate here.

Constant Summary collapse

LANGUAGE =
"ruby".freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config:, transport: nil, autostart: true) ⇒ Client

Returns a new instance of Client.



14
15
16
17
18
19
20
21
22
23
24
# File 'lib/beacon/client.rb', line 14

def initialize(config:, transport: nil, autostart: true)
  @config    = config
  @enabled   = config.enabled?
  # When disabled, build no transport and no flusher — the no-op
  # path does not touch the network and does not spawn threads.
  @transport = transport || (@enabled ? Transport::Http.new(config) : nil)
  @queue     = Beacon::Queue.new(max: config.queue_size, flush_threshold: config.flush_threshold)
  @pid       = Process.pid
  @mutex     = Mutex.new
  start_flusher if autostart && @enabled && config.async
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



12
13
14
# File 'lib/beacon/client.rb', line 12

def config
  @config
end

#flusherObject (readonly)

Returns the value of attribute flusher.



12
13
14
# File 'lib/beacon/client.rb', line 12

def flusher
  @flusher
end

#queueObject (readonly)

Returns the value of attribute queue.



12
13
14
# File 'lib/beacon/client.rb', line 12

def queue
  @queue
end

Instance Method Details

#after_forkObject

Re-spawn flusher in a forked child. Hosted servers (Puma clustered, Unicorn, Passenger) MUST call this in their on_worker_boot hook. Beacon detects forks lazily on the next push too — but explicit is cheaper than waiting for the first event.



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/beacon/client.rb', line 81

def after_fork
  @mutex.synchronize do
    @pid     = Process.pid
    @queue   = Beacon::Queue.new(max: @config.queue_size, flush_threshold: @config.flush_threshold)
    @flusher = nil
    # Drop any socket FD inherited from the parent — sharing one
    # across parent and child is undefined. The transport will
    # re-open lazily on the child's first flush.
    @transport.after_fork if @transport.respond_to?(:after_fork)
    start_flusher if @enabled && @config.async
  end
end

#enabled?Boolean

Returns:

  • (Boolean)


56
57
58
# File 'lib/beacon/client.rb', line 56

def enabled?
  @enabled
end

#flushObject



68
69
70
# File 'lib/beacon/client.rb', line 68

def flush
  @flusher&.flush_now
end

#push(event) ⇒ Object Also known as: <<

Sink interface — what middleware and integrations push into.



49
50
51
52
53
# File 'lib/beacon/client.rb', line 49

def push(event)
  return nil unless @enabled
  ensure_forked!
  @queue.push(event)
end

#shutdownObject



72
73
74
75
# File 'lib/beacon/client.rb', line 72

def shutdown
  @flusher&.stop
  @flusher = nil
end

#track(name, properties = {}) ⇒ Object

Outcomes API. The :user shorthand is the only magic — everything else in the properties hash flows through unchanged.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/beacon/client.rb', line 28

def track(name, properties = {})
  return nil unless @enabled
  return nil unless @config.pillar?(:outcomes)
  props      = properties.dup
  actor_type, actor_id = extract_actor(props)

  push({
    kind:          :outcome,
    name:          name.to_s,
    created_at_ns: realtime_ns,
    actor_type:    actor_type,
    actor_id:      actor_id,
    properties:    props,
    context:       base_context,
  })
rescue => e
  warn "[beacon] track failed: #{e.class}: #{e.message}"
  nil
end

#transport_reconnectsObject

Reconnect counter passthrough for Beacon.stats. Returns 0 when no transport is held (disabled client) or when the transport doesn’t implement the counter (test doubles).



63
64
65
66
# File 'lib/beacon/client.rb', line 63

def transport_reconnects
  return 0 unless @transport && @transport.respond_to?(:reconnects)
  @transport.reconnects
end