36
Long-Running Tasks In Rails Without Much Effort Andy Stewart April 2008

Handling Long-Running Tasks in Rails

Embed Size (px)

Citation preview

Page 1: Handling Long-Running Tasks in Rails

Long-Running Tasks In RailsWithout Much Effort

Andy Stewart

April 2008

Page 2: Handling Long-Running Tasks in Rails

Not me

Page 3: Handling Long-Running Tasks in Rails

Still not me

Page 4: Handling Long-Running Tasks in Rails

Why?

Page 5: Handling Long-Running Tasks in Rails
Page 6: Handling Long-Running Tasks in Rails

User startssomething

lengthy

Page 7: Handling Long-Running Tasks in Rails

Delayedtask

Page 8: Handling Long-Running Tasks in Rails

Regulartask

Page 9: Handling Long-Running Tasks in Rails

Example

Page 10: Handling Long-Running Tasks in Rails

Synchronous link to Campaign Monitor

Page 11: Handling Long-Running Tasks in Rails
Page 12: Handling Long-Running Tasks in Rails
Page 13: Handling Long-Running Tasks in Rails

10

Page 14: Handling Long-Running Tasks in Rails

BackgroundJob (BJ)

Delayed Job (DJ)

BackgrounDRbBeanstalkd &

async-observer

AM4R

Workling

Spawn

BackgroundFu

Sparrow

Conveyor

Page 15: Handling Long-Running Tasks in Rails

Factors

Page 16: Handling Long-Running Tasks in Rails

DurabilityProgress reporting

SchedulingSerial vs. Parallel

Process managementExecution environment

Error handlingLearning curve

Installation burdenConstraints on task code

Page 17: Handling Long-Running Tasks in Rails

Durability

Page 18: Handling Long-Running Tasks in Rails

Durable Hopeful

Background JobBackgroundFuDelayed JobWorkling

BackgrounDRbBeanstalk

SpawnSparrowWorkling

Page 19: Handling Long-Running Tasks in Rails

50%0% 100%

Page 20: Handling Long-Running Tasks in Rails

Tool Method

Background Job Process’s stats

BackgroundFu Incremental

BackgrounDRb Ask workers

Workling DIY “return store”

Page 21: Handling Long-Running Tasks in Rails

Scheduling

Page 22: Handling Long-Running Tasks in Rails

BackgrounDRb

cron + {rake, script/runner, whatever}

Page 23: Handling Long-Running Tasks in Rails

Delaying(on purpose)

Delayed Job

Beanstalk

Page 24: Handling Long-Running Tasks in Rails

ProcessManagement

Page 25: Handling Long-Running Tasks in Rails

No Problem Hassle

Background JobSpawn

Everything else

Page 26: Handling Long-Running Tasks in Rails

Examples

Page 27: Handling Long-Running Tasks in Rails

BackgrounDRb

# Lots of configuration...

# Your worker codeclass BillingWorker < BackgrounDRb::MetaWorker set_worker_name :billing_worker

# Called when worker is loaded for the first time def create(args = nil) end

# The lengthy task. def charge_customer(customer_id = nil) # ... do stuff ... endend

# Your invocation codeclass CustomersController < ApplicationController def upgrade_account # ... MiddleMan.worker(:billing_worker).charge_customer(@customer.id) endend

Page 28: Handling Long-Running Tasks in Rails

Beanstalk# Some configuration...

# Comments controllerdef create @comment = Comment.new(params[:comment]) if @comment.save BEANSTALK.yput({:type => "comment", :id => @comment.id}) rescue nil # Then redirect and return endend

# Worker - Rake taskloop do job = BEANSTALK.reserve job_hash = job.ybody # ybody deserializes the job case job_hash[:type] when "comment" if Comment.check_for_spam(job_hash[:id]) job.delete else job.bury end else puts "Don't know what type of job this is: #{job_hash.inspect}" endend

Source: nubyonrails.com

Page 29: Handling Long-Running Tasks in Rails

Async Observer

# Some configuration...

# Start some workers$ ./vendor/plugins/async_observer/bin/worker

# Your codeclass Person < ActiveRecord::Base async_after_create do |person| SiteStats.increment_members() end

def befriend(other_person) Friendship.async_send(:create, self, other_person) endend

Page 30: Handling Long-Running Tasks in Rails

Delayed Job

# Small config - db migration

# A job is a Ruby object with #performclass NewsletterJob < Struct.new(:text, :emails) def perform emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) } endend

# Stick in queueDelayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).collect(&:email))

# Delayed jobBatchImporter.new(Shop.find(1)).send_later(:import_massive_csv, massive_csv)

# Running tasks$ rake jobs:work <CTRL-C to cancel>

Page 31: Handling Long-Running Tasks in Rails

Background Job

# Command line

$ Bj.submit "./jobs/background_job_to_run"

$ Bj.submit "./script/runner ./jobs/background_job_to_run"

# Within Rails

def upload_to_s3 Bj.submit "./script/runner ./jobs/s3_uploader.rb #{self.id}" end

Source: slackworks.com

Page 32: Handling Long-Running Tasks in Rails

1

Page 33: Handling Long-Running Tasks in Rails

Background Job

Two-line installationZero configuration

No job-code constraintsAutomatic* process managementDurable, prioritised, taggable jobs

Comprehensive job resultsClustering

* Manual if you want

Page 34: Handling Long-Running Tasks in Rails

Feed my spaniel

Page 35: Handling Long-Running Tasks in Rails

Buy my PeepCode PDF

Page 36: Handling Long-Running Tasks in Rails

Text’s Licence:Creative Commons Attribution-Share Alike 2.0 UK: England & Wales Licence

My Photos’ Licence:Creative Commons Attribution-Noncommercial-No Derivative Works 2.0

UK: England & Wales Licence

Photo Credits:1. BBC2. Forever in Song (CD cover)3. Me4. Me