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