Packages
new_relic_agent
1.38.0
1.40.3
1.40.2
1.40.1
1.40.0
1.39.0
1.38.0
1.37.0
1.36.0
1.35.0
1.34.0
1.33.0
1.32.0
1.31.1
1.31.0
1.30.0
1.29.0
1.28.0
1.27.8
1.27.7
1.27.6
1.27.5
1.27.4
1.27.3
1.27.2
1.27.1
1.27.0
1.26.0
1.25.3
1.25.2
1.25.1
1.25.0
1.24.5
1.24.4
1.24.3
1.24.2
1.24.1
1.24.0
1.24.0-rc.10
1.24.0-rc.9
1.24.0-rc.8
1.24.0-rc.7
1.23.6
1.23.5
1.23.4
1.23.3
1.23.2
1.23.1
1.23.0
1.23.0-rc.6
1.23.0-rc.5
1.23.0-rc.4
1.23.0-rc.3
1.23.0-rc.2
1.23.0-rc.1
1.22.6
1.22.5
1.22.4
1.22.3
1.22.2
1.22.1
1.22.0
1.21.2
1.21.1
1.21.0
1.21.0-rc.3
1.21.0-rc.1
1.20.0
1.20.0-rc.1
1.19.7
1.19.6
1.19.5
1.19.4
1.19.3
1.19.2
1.19.1
1.19.0
1.18.5
1.18.4
1.18.3
1.18.2
1.18.1
1.18.0
1.18.0-rc.5
1.18.0-rc.4
1.18.0-rc.2
1.18.0-rc.1
1.17.1
1.17.0
1.17.0-rc.4
1.17.0-rc.3
1.17.0-rc.2
1.17.0-rc.1
1.17.0-rc.0
1.16.7
1.16.6
1.16.5
1.16.4
1.16.3
1.16.2
1.16.1
1.16.0
1.16.0-rc.2
1.16.0-rc.1
1.16.0-rc.0
1.15.0
1.15.0-rc.3
1.15.0-rc.2
1.15.0-rc.1
1.14.0
1.13.1
1.13.0
1.12.0
1.11.0
1.10.2
1.10.1
1.10.0
1.9.12
1.9.11
1.9.10
1.9.9
1.9.8
1.9.7
1.9.6
1.9.5
1.9.4
1.9.3
1.9.2
1.9.1
1.9.0
1.8.0
1.7.0
1.6.2
1.6.1
1.6.0
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.0
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
New Relic's Open-Source Elixir Agent
Current section
Files
Jump to
Current section
Files
lib/new_relic/harvest/harvest_cycle.ex
defmodule NewRelic.Harvest.HarvestCycle do
use GenServer
# Manages the harvest cycle for a given harvester.
@moduledoc false
alias NewRelic.Harvest
alias NewRelic.Harvest.HarvesterStore
def start_link(config) do
GenServer.start_link(__MODULE__, config, name: config[:name])
end
def init(
name: name,
child_spec: child_spec,
harvest_cycle_key: harvest_cycle_key,
supervisor: supervisor,
lookup_module: lookup_module
) do
if NewRelic.Config.enabled?(), do: send(self(), :harvest_cycle)
{:ok,
%{
name: name,
child_spec: child_spec,
harvest_cycle_key: harvest_cycle_key,
supervisor: supervisor,
lookup_module: lookup_module,
harvester: nil,
timer: nil
}}
end
# API
def current_harvester(harvest_cycle), do: HarvesterStore.current(harvest_cycle)
def cycle(harvest_cycle) do
send(harvest_cycle, :harvest_cycle)
end
def manual_shutdown(harvest_cycle) do
case current_harvester(harvest_cycle) do
nil ->
:ignore
harvester ->
Process.monitor(harvester)
GenServer.call(harvest_cycle, :pause)
receive do
{:DOWN, _ref, _, ^harvester, _reason} ->
NewRelic.log(:warning, "Completed shutdown #{inspect(harvest_cycle)}")
end
end
end
# Server
def handle_call(:restart, _from, %{timer: timer} = state) do
stop_harvest_cycle(timer)
harvester = swap_harvester(state)
timer = trigger_harvest_cycle(state)
{:reply, :ok, %{state | harvester: harvester, timer: timer}}
end
def handle_call(:pause, _from, %{timer: old_timer} = state) do
stop_harvester(state)
stop_harvest_cycle(old_timer)
{:reply, :ok, %{state | harvester: nil, timer: nil}}
end
def handle_info(:harvest_cycle, state) do
stop_harvest_cycle(state.timer)
harvester = swap_harvester(state)
timer = trigger_harvest_cycle(state)
{:noreply, %{state | harvester: harvester, timer: timer}}
end
def handle_info(
{:DOWN, _ref, _, pid, _reason},
%{harvester: crashed_harvester, timer: old_timer} = state
)
when pid == crashed_harvester do
stop_harvest_cycle(old_timer)
harvester = swap_harvester(state)
timer = trigger_harvest_cycle(state)
{:noreply, %{state | harvester: harvester, timer: timer}}
end
def handle_info({:DOWN, _ref, _, _pid, _reason}, state) do
{:noreply, state}
end
def handle_info(_msg, state) do
{:noreply, state}
end
# Helpers
defp swap_harvester(%{
supervisor: supervisor,
name: name,
harvester: harvester,
child_spec: child_spec
}) do
{:ok, next} = Harvest.HarvesterSupervisor.start_child(supervisor, child_spec)
Process.monitor(next)
HarvesterStore.update(name, next)
send_harvest(supervisor, harvester)
next
end
defp stop_harvester(%{supervisor: supervisor, name: name, harvester: harvester}) do
HarvesterStore.update(name, nil)
send_harvest(supervisor, harvester)
end
def send_harvest(_supervisor, nil), do: :no_harvester
@harvest_timeout 15_000
def send_harvest(supervisor, harvester) do
Task.Supervisor.start_child(
Harvest.TaskSupervisor,
fn ->
try do
GenServer.call(harvester, :send_harvest, @harvest_timeout)
catch
:exit, _exit ->
NewRelic.log(:error, "Failed to send harvest from #{inspect(supervisor)}")
after
DynamicSupervisor.terminate_child(supervisor, harvester)
end
end,
shutdown: @harvest_timeout
)
end
defp stop_harvest_cycle(timer), do: timer && Process.cancel_timer(timer)
defp trigger_harvest_cycle(%{
lookup_module: lookup_module,
harvest_cycle_key: harvest_cycle_key
}) do
harvest_cycle = lookup_module.lookup(harvest_cycle_key) || 60_000
Process.send_after(self(), :harvest_cycle, harvest_cycle)
end
end