Extending Gems
Jason Clark
@jasonrclark
Ruby Agent Engineer
Patterns and Anti-Patterns of
Pluggable Gems
Thursday, June 26, 14
Slide 2
Slide 2 text
Storytime!
Thursday, June 26, 14
Slide 3
Slide 3 text
newrelic_rpm
module NewRelic::Agent::BrowserMonitoring
def browser_monitoring_queue_time
queue_time = current_transaction.queue_time
millis = queue_time.to_f * 1000.0
clamp_to_positive(millis.round)
end
def footer_js_string(config)
"...#{browser_monitoring_queue_time}"
end
end
Thursday, June 26, 14
Slide 4
Slide 4 text
module NewRelic::Agent::BrowserMonitoring
def current_timings
TransactionTimings.new
end
def footer_js_string(config)
"...#{current_timings.queue_time_in_millis}"
end
end
newrelic_rpm
Thursday, June 26, 14
Slide 5
Slide 5 text
Meanwhile...
Elsewhere At New Relic
http://flic.kr/p/9xEUug
Thursday, June 26, 14
Slide 6
Slide 6 text
module NewRelic::Agent::BrowserMonitoring
# MONKEY PATCH!
def footer_js_string(config)
"...#{browser_monitoring_queue_time}"
end
end
rpm_site
Thursday, June 26, 14
Slide 7
Slide 7 text
http://pixabay.com/en/elephant-foot-ten-foot-elephant-52536/
Thursday, June 26, 14
Slide 8
Slide 8 text
Thursday, June 26, 14
Slide 9
Slide 9 text
Reskiq
It forks then it threads!
Thursday, June 26, 14
Slide 10
Slide 10 text
gem install
my_awesome_code
Thursday, June 26, 14
Slide 11
Slide 11 text
Where We're Going
• Pass It On
• Events
• Middleware
• Lifecycle
• Names and Paths
• Config
• Docs
Thursday, June 26, 14
Slide 12
Slide 12 text
Pass It On
Thursday, June 26, 14
Slide 13
Slide 13 text
Loggers
Thursday, June 26, 14
Slide 14
Slide 14 text
activerecord
ActiveRecord::Base.logger =
::Logger.new("my_special.log")
Thursday, June 26, 14
Slide 15
Slide 15 text
http://flic.kr/p/7GDRue
Dependency Injection
Thursday, June 26, 14
Slide 16
Slide 16 text
http://flic.kr/p/gzxjKu
Duck Typing
Thursday, June 26, 14
excon
class SimpleInstrumentor
class << self
def instrument(name, params = {}, &blk)
puts "#{name} just happened."
yield if block_given?
end
end
end
Thursday, June 26, 14
Slide 20
Slide 20 text
http://pixabay.com/en/elephant-foot-ten-foot-elephant-52536/
Thursday, June 26, 14
Slide 21
Slide 21 text
Backends
Thursday, June 26, 14
Slide 22
Slide 22 text
Delayed::Job
# without delayed_job
@user.activate!(@device)
# with delayed_job
@user.delay.activate!(@device)
Thursday, June 26, 14
Slide 23
Slide 23 text
Delayed::Job
Thursday, June 26, 14
Slide 24
Slide 24 text
Delayed::Job
::Delayed.const_set(:Job, backend)
Thursday, June 26, 14
Slide 25
Slide 25 text
newrelic_rpm
def failed_jobs
Delayed::Job.count(
:conditions => 'failed_at is not NULL')
end
Thursday, June 26, 14
Slide 26
Slide 26 text
Gem-Specific
Thursday, June 26, 14
Slide 27
Slide 27 text
Resque
class SendMessageJob
def self.perform(id, text)
user = User.find(id)
user.send_message(text)
end
end
Resque.enqueue(SendMessageJob, 42, "Yo")
Thursday, June 26, 14
Slide 28
Slide 28 text
Resque
https://github.com/resque/resque/blob/master/docs/HOOKS.md
class SendMessageJob
def self.before_perform_log_it(*args)
logger.debug("Messaging #{args}")
end
...
end
Thursday, June 26, 14
Slide 29
Slide 29 text
Where We've Been
• Pass It On
• Events
• Middleware
• Lifecycle
• Names and Paths
• Config
• Docs
Thursday, June 26, 14
Slide 30
Slide 30 text
Events
Thursday, June 26, 14
Slide 31
Slide 31 text
http://www.confreaks.com/videos/3327-railsconf-
make-an-event-of-it
Thursday, June 26, 14
Slide 32
Slide 32 text
Resque
Resque.after_fork do |job|
ActiveRecord::Base.establish_connection
end
Thursday, June 26, 14
Slide 33
Slide 33 text
http://pixabay.com/en/elephant-foot-ten-foot-elephant-52536/
Thursday, June 26, 14
Slide 34
Slide 34 text
Where We've Been
• Pass It On
• Events
• Middleware
• Lifecycle
• Names and Paths
• Config
• Docs
Thursday, June 26, 14
Slide 35
Slide 35 text
Middleware
Thursday, June 26, 14
Slide 36
Slide 36 text
Rack::Cache
ActionDispatch::Cookies
YourApplication
Web Request
Thursday, June 26, 14
Slide 37
Slide 37 text
# [status, headers, response]
def call(env)
# ... before
result = @app.call(env)
# ... after
result
end
Thursday, June 26, 14
Slide 38
Slide 38 text
# [status, headers, response]
def call(env)
# ... before
result = @app.call(env)
# ... after
result
end
Thursday, June 26, 14
unicorn
worker_processes 5
preload_app true
timeout 30
after_fork do |server, worker|
defined?(ActiveRecord::Base) and
ActiveRecord::Base.establish_connection
end
Thursday, June 26, 14
Slide 88
Slide 88 text
on_worker_boot do
ActiveSupport.on_load(:active_record) do
ActiveRecord::Base.establish_connection
end
end
Thursday, June 26, 14
Slide 89
Slide 89 text
Great for Apps?
What about Gems?
Thursday, June 26, 14
Slide 90
Slide 90 text
newrelic_rpm
if defined?(::Puma) &&
::Puma.respond_to?(:cli_config)
config = ::Puma.cli_config
config.options[:worker_boot] << Proc.new do
NewRelic::Agent.after_fork(...)
end
end
Thursday, June 26, 14
Slide 91
Slide 91 text
newrelic_rpm
if defined?(::Puma) &&
::Puma.respond_to?(:cli_config)
config = ::Puma.cli_config
config.options[:worker_boot] << Proc.new do
NewRelic::Agent.after_fork(...)
end
end
Thursday, June 26, 14
Slide 92
Slide 92 text
Where We've Been
• Pass It On
• Events
• Middleware
• Lifecycle
• Names and Paths
• Config
• Docs
Thursday, June 26, 14
Slide 93
Slide 93 text
Docs
Thursday, June 26, 14
Slide 94
Slide 94 text
README
Thursday, June 26, 14
Slide 95
Slide 95 text
sinatra
Thursday, June 26, 14
Slide 96
Slide 96 text
Thursday, June 26, 14
Slide 97
Slide 97 text
Thursday, June 26, 14
Slide 98
Slide 98 text
Thursday, June 26, 14
Slide 99
Slide 99 text
Expected
Extensions?
Thursday, June 26, 14
Slide 100
Slide 100 text
Thursday, June 26, 14
Slide 101
Slide 101 text
Don't Bury It
Thursday, June 26, 14
Slide 102
Slide 102 text
Thursday, June 26, 14
Slide 103
Slide 103 text
Thursday, June 26, 14
Slide 104
Slide 104 text
Versioning
Thursday, June 26, 14
Slide 105
Slide 105 text
Thursday, June 26, 14
Slide 106
Slide 106 text
Where We've Been
• Pass It On
• Events
• Middleware
• Lifecycle
• Names and Paths
• Config
• Docs
Thursday, June 26, 14
Slide 107
Slide 107 text
Where We've Been
Thursday, June 26, 14
Slide 108
Slide 108 text
Where We've Been
• Pass It On
• Events
• Middleware
• Lifecycle
• Names and Paths
• Config
• Docs
Thursday, June 26, 14
Slide 109
Slide 109 text
Where We've Been
• Pass It On
• Events
• Middleware
• Lifecycle
• Names and Paths
• Config
• Docs
Jason Clark
@jasonrclark
Ruby Agent Engineer
Thursday, June 26, 14