lib/new_relic/agent/agent.rb in newrelic_rpm-3.6.7.152 vs lib/new_relic/agent/agent.rb in newrelic_rpm-3.6.7.159.beta
- old
+ new
@@ -44,11 +44,11 @@
@events = NewRelic::Agent::EventListener.new
@stats_engine = NewRelic::Agent::StatsEngine.new
@transaction_sampler = NewRelic::Agent::TransactionSampler.new
@sql_sampler = NewRelic::Agent::SqlSampler.new
@thread_profiler = NewRelic::Agent::Commands::ThreadProfiler.new
- @agent_command_router = NewRelic::Agent::Commands::AgentCommandRouter.new(@service, @thread_profiler)
+ @agent_command_router = NewRelic::Agent::Commands::AgentCommandRouter.new(@thread_profiler)
@cross_app_monitor = NewRelic::Agent::CrossAppMonitor.new(@events)
@error_collector = NewRelic::Agent::ErrorCollector.new
@transaction_rules = NewRelic::Agent::RulesEngine.new
@metric_rules = NewRelic::Agent::RulesEngine.new
@request_sampler = NewRelic::Agent::RequestSampler.new(@events)
@@ -535,10 +535,11 @@
# Clear out state for any objects that we know lock from our parents
# This is necessary for cases where we're in a forked child and Ruby
# might be holding locks for background thread that aren't there anymore.
def reset_objects_with_locks
@stats_engine = NewRelic::Agent::StatsEngine.new
+ reset_harvest_locks
end
def add_harvest_sampler(subclass)
@harvest_samplers.add_sampler(subclass)
end
@@ -552,9 +553,37 @@
# logs info about the worker loop so users can see when the
# agent actually begins running in the background
def log_worker_loop_start
::NewRelic::Agent.logger.debug "Reporting performance data every #{Agent.config[:data_report_period]} seconds."
::NewRelic::Agent.logger.debug "Running worker loop"
+ end
+
+ # Accessor for the harvest lock
+ def harvest_lock
+ return nil if @worker_loop.nil?
+ @worker_loop.lock
+ end
+
+ # Synchronize with the harvest loop. If the harvest thread has taken
+ # a lock (DNS lookups, backticks, agent-owned locks, etc), and we
+ # fork while locked, this can deadlock child processes. For more
+ # details, see https://github.com/resque/resque/issues/1101
+ def synchronize_with_harvest
+ if harvest_lock
+ harvest_lock.synchronize do
+ yield
+ end
+ else
+ yield
+ end
+ end
+
+ # Some forking cases (like Resque) end up with harvest lock from the
+ # parent process orphaned in the child. Let it go before we proceed.
+ def reset_harvest_locks
+ return if harvest_lock.nil?
+
+ harvest_lock.unlock if harvest_lock.locked?
end
# Creates the worker loop and loads it with the instructions
# it should run every @report_period seconds
def create_and_run_worker_loop