Dec 2
Inspired by gist from DHH I bring you simple recipe for slightly more powerful soft deletes. Main feature is adding before_trash and after_trash callbacks by utilizing define_model_callbacks. Another nice-to-have is recording timestamp of deletion.
Recommended reading for this and another patterns for soft-deletes is Richard Dingwall’s article.
Nov 30
Clockwork is simple and very useful tool for scheduling tasks instead of using cron jobs in ruby.
First things first, add clockwork to your Gemfile:
Configuration is kept in config/clock.rb. It uses plain ruby DSL. Most amazing thing is to use custom handler which allows you to skip loading Rails environment and insert scheduled jobs directly into delyed job database table.
require 'pg'
require 'yaml'
db = YAML.load_file(File.dirname(__FILE__) + "/database.yml")[ENV['RAILS_ENV'] || "development"]
conn = PGconn.connect(db['host'], nil, nil, nil, db['database'], db['username'], db['password'])
require 'clockwork'
include Clockwork
handler do |job|
db_time = Time.now.utc.strftime("%Y-%m-%d %H:%M:%S")
handler = "--- !ruby/object:ScheduledJob \njob: #{job}\n"
conn.exec("INSERT INTO \"delayed_jobs\" (\"failed_at\", \"locked_by\", \"created_at\", \"handler\", \"updated_at\", \"priority\", \"run_at\", \"attempts\", \"locked_at\", \"last_error\") VALUES(NULL, NULL, '#{db_time}', '#{handler}', '#{db_time}', 0, '#{db_time}', 0, NULL, NULL)")
end
every(30.minutes, 'reactivate_paid_accounts')
And finally example of ScheduledJob:
class ScheduledJob
attr_accessor :job
SUPPORTED_JOBS = {
:reactivate_paid_accounts => 'Account.reactivate_paid'
}
def initialize(job)
self.job = job
unless SUPPORTED_JOBS.has_key?(job.to_sym)
raise "Unsupported scheduled action - #{job}"
end
end
def perform
klass, method = SUPPORTED_JOBS[job.to_sym].split('.')
Kernel.const_get(klass).send(method.to_sym)
end
def display_name
"Job/#{job}"
end
end
Jul 16
Motivation: your logs are growing request by request and your free disk space is smaller and smaller. Solution is log rotation with logrotate.
Requirements:
- nginx + passenger (installed in
/opt/nginx)
- logrotate (
aptitude install logrotate)
- capistrano (deploying into
/home/web/YOUR_APPLICATION_NAME)
- logs to rotate (
production.log, access.log, error.log, newrelic_agent.log, …)
Capistrano part
Logrotate configuration will be generated from ERB template:
# logrotate.erb.conf
# Logrotate config for <%= application %>
# Generated at <%= Time.now.strftime("%d.%m.%Y, %H:%M") %>
<%= shared_path %>/log/*.log {
daily
missingok
rotate 30
compress
delaycompress
sharedscripts
olddir <%= shared_path %>/log/old
postrotate
test ! -f /opt/nginx/logs/nginx.pid || kill -USR1 `cat /opt/nginx/logs/nginx.pid`
endscript
}
Notes:
- old logs moved under
old directory, compressed and kept for 30 days
- no slow
copytruncate, after rotation of all logs in directory (sharedscripts) send USR1 signal to nginx to reopen logs
To generate logrotate configuration use following capistrano task:
namespace :logrotate do
desc "Create logrotate configuration file"
task :create_conf, :roles => :web do
template = File.read(File.join(File.dirname(__FILE__), "logrotate.conf.erb"))
buffer = ERB.new(template).result(binding)
put buffer, "#{shared_path}/config/logrotate.conf"
end
end
after 'setup', 'logrotate:create_conf'
Server part
To include generated configuration file add following to server’s /etc/logrotate.conf
include /home/web/YOUR_APPLICATION_NAME/shared/config/logrotate.conf
To ensure periodic rotation logrotate relies on daily execution by cron. In Debian it is placed in /etc/cron.daily/logrotate.
Resume
I have seen examples promoting virtual host generation from ERB template by capistrano tasks but why not apply it to generating logrotate configuration? You got it bundled (and versioned) with your application sources and that is big win.