Class: Appsignal::CheckIn::Scheduler

Inherits:
Object
  • Object
show all
Defined in:
lib/appsignal/check_in/scheduler.rb

Constant Summary collapse

INITIAL_DEBOUNCE_SECONDS =
0.1
BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS =
10

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeScheduler

Returns a new instance of Scheduler.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/appsignal/check_in/scheduler.rb', line 9

def initialize
  # The mutex is used to synchronize access to the events array, the
  # waker thread and the main thread, as well as queue writes
  # (which depend on the events array) and closes (so they do not
  # happen at the same time that an event is added to the scheduler)
  @mutex = Mutex.new
  # The transmitter thread will be started when an event is first added.
  @thread = nil
  @queue = Thread::Queue.new
  # Scheduled events that have not been sent to the transmitter thread
  # yet. A copy of this array is pushed to the queue by the waker thread
  # after it has awaited the debounce period.
  @events = []
  # The waker thread is used to schedule debounces. It will be started
  # when an event is first added.
  @waker = nil
  # For internal testing purposes.
  @transmitted = 0
end

Instance Attribute Details

#eventsObject (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.

For internal testing purposes.



80
81
82
# File 'lib/appsignal/check_in/scheduler.rb', line 80

def events
  @events
end

#queueObject (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.

For internal testing purposes.



80
81
82
# File 'lib/appsignal/check_in/scheduler.rb', line 80

def queue
  @queue
end

#threadObject (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.

For internal testing purposes.



80
81
82
# File 'lib/appsignal/check_in/scheduler.rb', line 80

def thread
  @thread
end

#transmittedObject (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.

For internal testing purposes.



80
81
82
# File 'lib/appsignal/check_in/scheduler.rb', line 80

def transmitted
  @transmitted
end

#wakerObject (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.

For internal testing purposes.



80
81
82
# File 'lib/appsignal/check_in/scheduler.rb', line 80

def waker
  @waker
end

Instance Method Details

#schedule(event) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/appsignal/check_in/scheduler.rb', line 29

def schedule(event)
  unless Appsignal.active?
    Appsignal.internal_logger.debug(
      "Cannot transmit #{Event.describe([event])}: AppSignal is not active"
    )
    return
  end

  @mutex.synchronize do
    if @queue.closed?
      Appsignal.internal_logger.debug(
        "Cannot transmit #{Event.describe([event])}: AppSignal is stopped"
      )
      return
    end
    add_event(event)
    # If we're not already waiting to be awakened from a scheduled
    # debounce, schedule a short debounce, which will push the events
    # to the queue and schedule a long debounce.
    start_waker(INITIAL_DEBOUNCE_SECONDS) if @waker.nil?

    Appsignal.internal_logger.debug(
      "Scheduling #{Event.describe([event])} to be transmitted"
    )

    # Make sure to start the thread after an event has been added.
    @thread ||= Thread.new(&method(:run))
  end
end

#stopObject



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/appsignal/check_in/scheduler.rb', line 59

def stop
  @mutex.synchronize do
    # Flush all events before closing the queue.
    push_events
  rescue ClosedQueueError
    # The queue is already closed (by a previous call to `#stop`)
    # so it is not possible to push events to it anymore.
  ensure
    # Ensure calling `#stop` closes the queue and kills
    # the waker thread, disallowing any further events from being
    # scheduled with `#schedule`.
    stop_waker
    @queue.close

    # Block until the thread has finished.
    @thread&.join
  end
end