diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2014-05-19 12:06:09 +0200 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2014-05-19 12:06:09 +0200 |
commit | 211ce71400449c7e65cbef8ba9546418a20b3c8f (patch) | |
tree | 46715d030772f963621efa600e4a9cf2ee1faf93 | |
parent | 65bf5f101e1105411afe030887fbe203d08dadbd (diff) | |
download | rails-211ce71400449c7e65cbef8ba9546418a20b3c8f.tar.gz rails-211ce71400449c7e65cbef8ba9546418a20b3c8f.tar.bz2 rails-211ce71400449c7e65cbef8ba9546418a20b3c8f.zip |
Add GlobalID support for serialization
-rw-r--r-- | Gemfile | 1 | ||||
-rw-r--r-- | Gemfile.lock | 13 | ||||
-rw-r--r-- | README.rdoc | 29 | ||||
-rw-r--r-- | lib/active_job/base.rb | 6 | ||||
-rw-r--r-- | lib/active_job/enqueuing.rb | 9 | ||||
-rw-r--r-- | lib/active_job/job_wrappers/delayed_job_wrapper.rb | 9 | ||||
-rw-r--r-- | lib/active_job/job_wrappers/resque_wrapper.rb | 4 | ||||
-rw-r--r-- | lib/active_job/job_wrappers/sidekiq_wrapper.rb | 4 | ||||
-rw-r--r-- | lib/active_job/job_wrappers/sucker_punch_wrapper.rb | 2 | ||||
-rw-r--r-- | lib/active_job/parameters.rb | 15 | ||||
-rw-r--r-- | lib/active_job/queue_adapters/delayed_job_adapter.rb | 3 | ||||
-rw-r--r-- | lib/active_job/queue_adapters/inline_adapter.rb | 2 | ||||
-rw-r--r-- | test/cases/job_serialization_test.rb | 15 | ||||
-rw-r--r-- | test/cases/parameters_test.rb | 31 | ||||
-rw-r--r-- | test/jobs/gid_job.rb | 6 | ||||
-rw-r--r-- | test/models/person.rb | 19 |
16 files changed, 157 insertions, 11 deletions
@@ -6,3 +6,4 @@ gem 'resque' gem 'sidekiq' gem 'sucker_punch' gem 'delayed_job' +gem 'activemodel-globalid', github: 'rails/activemodel-globalid'
\ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 7005cc4d46..e8e8e0eb18 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,11 @@ +GIT + remote: git://github.com/rails/activemodel-globalid.git + revision: c9d4cfa80e9234d178617338b22728e7c08498d1 + specs: + activemodel-globalid (0.1.0) + activemodel (>= 4.1.0) + activesupport (>= 4.1.0) + PATH remote: . specs: @@ -7,12 +15,16 @@ PATH GEM remote: https://rubygems.org/ specs: + activemodel (4.1.1) + activesupport (= 4.1.1) + builder (~> 3.1) activesupport (4.1.1) i18n (~> 0.6, >= 0.6.9) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) thread_safe (~> 0.1) tzinfo (~> 1.1) + builder (3.2.2) celluloid (0.15.2) timers (~> 1.1.0) connection_pool (2.0.0) @@ -60,6 +72,7 @@ PLATFORMS DEPENDENCIES activejob! + activemodel-globalid! delayed_job resque sidekiq diff --git a/README.rdoc b/README.rdoc index c83a5b2986..84d40809f7 100644 --- a/README.rdoc +++ b/README.rdoc @@ -11,6 +11,35 @@ one of the most common jobs in a modern web application: Sending emails outside of the request-response cycle, so the user doesn't have to wait on it. +== GlobalID support + +Active Job supports GlobalID serialization for parameters. This makes it possible +to pass live Active Record objects to your job instead of class/id pairs, which +you then have to manually deserialize. Before, jobs would look like this: + +```ruby +class TrashableCleanupJob + def self.perfom(trashable_class, trashable_id, depth) + trashable = trashable_class.constantize.find(trashable_id) + trashable.cleanup(depth) + end +end +``` + +Now you can simply do: + +```ruby +class TrashableCleanupJob + def self.perfom(trashable, depth) + trashable.cleanup(depth) + end +end +``` + +This works with any class that mixes in ActiveModel::GlobalIdentification, which +by default has been mixed into Active Record classes. + + == Supported queueing systems We currently have adapters for: diff --git a/lib/active_job/base.rb b/lib/active_job/base.rb index fe3d1677dd..77b929d4af 100644 --- a/lib/active_job/base.rb +++ b/lib/active_job/base.rb @@ -1,13 +1,11 @@ require 'active_job/queue_adapter' require 'active_job/queue_name' +require 'active_job/enqueuing' module ActiveJob class Base extend QueueAdapter extend QueueName - - def self.enqueue(*args) - queue_adapter.queue self, *args - end + extend Enqueuing end end
\ No newline at end of file diff --git a/lib/active_job/enqueuing.rb b/lib/active_job/enqueuing.rb new file mode 100644 index 0000000000..94a9dbf8ab --- /dev/null +++ b/lib/active_job/enqueuing.rb @@ -0,0 +1,9 @@ +require 'active_job/parameters' + +module ActiveJob + module Enqueuing + def enqueue(*args) + queue_adapter.queue self, *Parameters.serialize(args) + end + end +end
\ No newline at end of file diff --git a/lib/active_job/job_wrappers/delayed_job_wrapper.rb b/lib/active_job/job_wrappers/delayed_job_wrapper.rb new file mode 100644 index 0000000000..0868d7b570 --- /dev/null +++ b/lib/active_job/job_wrappers/delayed_job_wrapper.rb @@ -0,0 +1,9 @@ +module ActiveJob + module JobWrappers + class DelayedJobWrapper + def perform(job, *args) + job.perform(*ActiveJob::Parameters.deserialize(args)) + end + end + end +end diff --git a/lib/active_job/job_wrappers/resque_wrapper.rb b/lib/active_job/job_wrappers/resque_wrapper.rb index cbeee4fb1b..68d9b252ba 100644 --- a/lib/active_job/job_wrappers/resque_wrapper.rb +++ b/lib/active_job/job_wrappers/resque_wrapper.rb @@ -3,8 +3,6 @@ require 'resque' require 'active_support/core_ext/enumerable' require 'active_support/core_ext/array/access' - - module ActiveJob module JobWrappers class ResqueWrapper @@ -14,7 +12,7 @@ module ActiveJob end def perform(job_name, *args) - job_name.constantize.perform(*args) + job_name.constantize.perform(*ActiveJob::Parameters.deserialize(args)) end end diff --git a/lib/active_job/job_wrappers/sidekiq_wrapper.rb b/lib/active_job/job_wrappers/sidekiq_wrapper.rb index fb728ae0fd..e1332b0210 100644 --- a/lib/active_job/job_wrappers/sidekiq_wrapper.rb +++ b/lib/active_job/job_wrappers/sidekiq_wrapper.rb @@ -1,10 +1,12 @@ +require 'active_job/parameters' + module ActiveJob module JobWrappers class SidekiqWrapper include Sidekiq::Worker def perform(job_name, *args) - job_name.constantize.perform(*args) + job_name.constantize.perform(*ActiveJob::Parameters.deserialize(args)) end end end diff --git a/lib/active_job/job_wrappers/sucker_punch_wrapper.rb b/lib/active_job/job_wrappers/sucker_punch_wrapper.rb index 80648792ca..7e9960b44f 100644 --- a/lib/active_job/job_wrappers/sucker_punch_wrapper.rb +++ b/lib/active_job/job_wrappers/sucker_punch_wrapper.rb @@ -4,7 +4,7 @@ module ActiveJob include SuckerPunch::Job def perform(job_name, *args) - job_name.perform(*args) + job_name.perform(*ActiveJob::Parameters.deserialize(args)) end end end diff --git a/lib/active_job/parameters.rb b/lib/active_job/parameters.rb new file mode 100644 index 0000000000..a4841abd1e --- /dev/null +++ b/lib/active_job/parameters.rb @@ -0,0 +1,15 @@ +require 'active_model/global_locator' +require 'active_support/core_ext/object/try' + +module ActiveJob + class Parameters + def self.serialize(params) + params.collect { |param| param.try(:global_id) || param } + end + + def self.deserialize(params) + params.collect { |param| ActiveModel::GlobalLocator.locate(param) || param } + end + end +end +
\ No newline at end of file diff --git a/lib/active_job/queue_adapters/delayed_job_adapter.rb b/lib/active_job/queue_adapters/delayed_job_adapter.rb index 33229dece4..4730d97a9a 100644 --- a/lib/active_job/queue_adapters/delayed_job_adapter.rb +++ b/lib/active_job/queue_adapters/delayed_job_adapter.rb @@ -1,11 +1,12 @@ require 'delayed_job' +require 'active_job/job_wrappers/delayed_job_wrapper' module ActiveJob module QueueAdapters class DelayedJobAdapter class << self def queue(job, *args) - job.delay(queue: job.queue_name).perform(*args) + JobWrappers::DelayedJobWrapper.new.delay(queue: job.queue_name).perform(job, *args) end end end diff --git a/lib/active_job/queue_adapters/inline_adapter.rb b/lib/active_job/queue_adapters/inline_adapter.rb index ac28670a29..0a1526dce7 100644 --- a/lib/active_job/queue_adapters/inline_adapter.rb +++ b/lib/active_job/queue_adapters/inline_adapter.rb @@ -3,7 +3,7 @@ module ActiveJob class InlineAdapter class << self def queue(job, *args) - job.perform(*args) + job.perform(*ActiveJob::Parameters.deserialize(args)) end end end diff --git a/test/cases/job_serialization_test.rb b/test/cases/job_serialization_test.rb new file mode 100644 index 0000000000..b1e24db22e --- /dev/null +++ b/test/cases/job_serialization_test.rb @@ -0,0 +1,15 @@ +require 'helper' +require 'jobs/gid_job' +require 'models/person' + +class JobSerializationTest < ActiveSupport::TestCase + setup do + $BUFFER = [] + @person = Person.find(5) + end + + test 'serialize job with gid' do + GidJob.enqueue @person + assert_equal "Person with ID: 5", $BUFFER.pop + end +end diff --git a/test/cases/parameters_test.rb b/test/cases/parameters_test.rb new file mode 100644 index 0000000000..eafa5a052b --- /dev/null +++ b/test/cases/parameters_test.rb @@ -0,0 +1,31 @@ +require 'helper' +require 'active_job/parameters' +require 'models/person' + +class ParameterSerializationTest < ActiveSupport::TestCase + test 'should make no change to regular values' do + assert_equal [ 1, "something" ], ActiveJob::Parameters.serialize([ 1, "something" ]) + end + + test 'should serialize records with global id' do + assert_equal [ Person.find(5).gid ], ActiveJob::Parameters.serialize([ Person.find(5) ]) + end + + test 'should serialize values and records together' do + assert_equal [ 3, Person.find(5).gid ], ActiveJob::Parameters.serialize([ 3, Person.find(5) ]) + end +end + +class ParameterDeserializationTest < ActiveSupport::TestCase + test 'should make no change to regular values' do + assert_equal [ 1, "something" ], ActiveJob::Parameters.deserialize([ 1, "something" ]) + end + + test 'should deserialize records with global id' do + assert_equal [ Person.find(5) ], ActiveJob::Parameters.deserialize([ Person.find(5).gid ]) + end + + test 'should serialize values and records together' do + assert_equal [ 3, Person.find(5) ], ActiveJob::Parameters.deserialize([ 3, Person.find(5).gid ]) + end +end diff --git a/test/jobs/gid_job.rb b/test/jobs/gid_job.rb new file mode 100644 index 0000000000..c1bfbb2655 --- /dev/null +++ b/test/jobs/gid_job.rb @@ -0,0 +1,6 @@ +class GidJob < ActiveJob::Base + def self.perform(person) + $BUFFER << "Person with ID: #{person.id}" + end +end +
\ No newline at end of file diff --git a/test/models/person.rb b/test/models/person.rb new file mode 100644 index 0000000000..6e91e8b9a2 --- /dev/null +++ b/test/models/person.rb @@ -0,0 +1,19 @@ +require 'active_model/global_identification' + +class Person + include ActiveModel::GlobalIdentification + + attr_reader :id + + def self.find(id) + new(id) + end + + def initialize(id) + @id = id + end + + def ==(other_person) + other_person.is_a?(Person) && id = other_person.id + end +end
\ No newline at end of file |