Class: NewRelic::Agent::WorkerLoop

Inherits:
Object
  • Object
show all
Defined in:
lib/new_relic/agent/worker_loop.rb

Overview

A worker loop executes a set of registered tasks on a single thread. A task is a proc or block with a specified call period in seconds.

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ WorkerLoop

Optional argument :duration (in seconds) for how long the worker loop runs or :limit (integer) for max number of iterations



11
12
13
14
15
16
17
18
19
# File 'lib/new_relic/agent/worker_loop.rb', line 11

def initialize(opts={})
  @log = log
  @should_run = true
  @next_invocation_time = Time.now
  @period = 60.0
  @deadline = Time.now + opts[:duration] if opts[:duration]
  @limit = opts[:limit] if opts[:limit]
  @iterations = 0
end

Instance Method Details

#keep_running?Boolean

a simple accessor for @should_run

Returns:

  • (Boolean)


51
52
53
54
# File 'lib/new_relic/agent/worker_loop.rb', line 51

def keep_running?
  @now = Time.now
  @should_run && under_duration? && under_limit?
end

#lockObject

returns a class-level memoized mutex to make sure we don’t run overlapping



22
23
24
# File 'lib/new_relic/agent/worker_loop.rb', line 22

def lock
  @@lock ||= Mutex.new
end

#logObject

a helper to access the NewRelic::Control.instance.log



27
28
29
# File 'lib/new_relic/agent/worker_loop.rb', line 27

def log
  NewRelic::Control.instance.log
end

#run(period = nil, &block) ⇒ Object

Run infinitely, calling the registered tasks at their specified call periods. The caller is responsible for creating the thread that runs this worker loop. This will run the task immediately.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/new_relic/agent/worker_loop.rb', line 34

def run(period=nil, &block)
  @period = period if period
  @next_invocation_time = (Time.now + @period)
  @task = block
  while keep_running? do
    while @now < @next_invocation_time
      # sleep until this next task's scheduled invocation time
      sleep_time = @next_invocation_time - @now
      sleep sleep_time if sleep_time > 0
      @now = Time.now
    end
    run_task if keep_running?
    @iterations += 1 if !@limit.nil?
  end
end

#run_taskObject

Executes the block given to the worker loop, and handles many possible errors. Also updates the execution time so that the next run occurs on schedule, even if we execute at some odd time



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/new_relic/agent/worker_loop.rb', line 72

def run_task
  begin
    lock.synchronize do
      @task.call
    end
  rescue ServerError => e
    log.debug "Server Error: #{e}"
  rescue NewRelic::Agent::ForceRestartException, NewRelic::Agent::ForceDisconnectException
    # blow out the loop
    raise
  rescue RuntimeError => e
    # This is probably a server error which has been logged in the server along
    # with your account name.
    log.error "Error running task in worker loop, likely a server error (#{e})"
    log.debug e.backtrace.join("\n")
  rescue Timeout::Error, NewRelic::Agent::ServerConnectionException
    # Want to ignore these because they are handled already
  rescue SystemExit, NoMemoryError, SignalException
    raise
  rescue => e
    # Don't blow out the stack for anything that hasn't already propagated
    log.error "Error running task in Agent Worker Loop '#{e}': #{e.backtrace.first}"
    log.debug e.backtrace.join("\n")
  end
  now = Time.now
  while @next_invocation_time <= now && @period > 0
    @next_invocation_time += @period
  end
end

#stopObject

Sets @should_run to false. Returns false



65
66
67
# File 'lib/new_relic/agent/worker_loop.rb', line 65

def stop
  @should_run = false
end

#under_duration?Boolean

Returns:

  • (Boolean)


56
57
58
# File 'lib/new_relic/agent/worker_loop.rb', line 56

def under_duration?
  !@deadline || @now < @deadline
end

#under_limit?Boolean

Returns:

  • (Boolean)


60
61
62
# File 'lib/new_relic/agent/worker_loop.rb', line 60

def under_limit?
  !@limit || @iterations < @limit
end