async-jobs 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ad313be63e58bd780e2b68297719ec64cb7f46e6
4
+ data.tar.gz: 4f341fc468bf497f4266185e930351c3a1c6ce1b
5
+ SHA512:
6
+ metadata.gz: eff272909fab9a45836846e6576762ef7e9da0bee6442e47aa769a3bc3be2d8eafdf0e33bed032dd37332ec69b410b0a1fe71d2e13ba25093585e571a8600352
7
+ data.tar.gz: 0fe48659523783bd0314e8c5b1e6425fd99bdba12f721c245bc36589d745c90466e73003e51388a8d1e573f4eaca3624aa6241f55446960856f8fe3f4ef3daee
@@ -0,0 +1 @@
1
+ async*.gem
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'redis'
7
+ gem 'cubbyhole', :require => false
8
+ gem 'qu'
9
+ gem 'rspec'
10
+ gem 'resque'
11
+ gem 'sidekiq'
12
+ end
@@ -0,0 +1,66 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ async-jobs (0.0.3)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ celluloid (0.12.4)
10
+ facter (>= 1.6.12)
11
+ timers (>= 1.0.0)
12
+ connection_pool (1.0.0)
13
+ cubbyhole (0.2.1)
14
+ diff-lcs (1.1.3)
15
+ facter (1.6.18)
16
+ multi_json (1.7.0)
17
+ qu (0.2.0)
18
+ multi_json
19
+ rack (1.4.5)
20
+ rack-protection (1.4.0)
21
+ rack
22
+ redis (3.0.2)
23
+ redis-namespace (1.2.1)
24
+ redis (~> 3.0.0)
25
+ resque (1.23.0)
26
+ multi_json (~> 1.0)
27
+ redis-namespace (~> 1.0)
28
+ sinatra (>= 0.9.2)
29
+ vegas (~> 0.1.2)
30
+ rspec (2.11.0)
31
+ rspec-core (~> 2.11.0)
32
+ rspec-expectations (~> 2.11.0)
33
+ rspec-mocks (~> 2.11.0)
34
+ rspec-core (2.11.1)
35
+ rspec-expectations (2.11.2)
36
+ diff-lcs (~> 1.1.3)
37
+ rspec-mocks (2.11.1)
38
+ sidekiq (2.8.0)
39
+ celluloid (~> 0.12.0)
40
+ connection_pool (~> 1.0)
41
+ multi_json (~> 1)
42
+ redis (~> 3)
43
+ redis-namespace
44
+ sinatra (1.3.5)
45
+ rack (~> 1.4)
46
+ rack-protection (~> 1.3)
47
+ tilt (~> 1.3, >= 1.3.3)
48
+ tilt (1.3.4)
49
+ timers (1.1.0)
50
+ vegas (0.1.11)
51
+ rack (>= 1.0.0)
52
+
53
+ PLATFORMS
54
+ ruby
55
+
56
+ DEPENDENCIES
57
+ async-jobs!
58
+ cubbyhole
59
+ qu
60
+ redis
61
+ resque
62
+ rspec
63
+ sidekiq
64
+
65
+ BUNDLED WITH
66
+ 1.12.5
@@ -0,0 +1,20 @@
1
+ Copyright (c) Engine Yard. All rights reserved.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ #Yet another background processing abstraction layer
2
+
3
+ Assuming that every time you want to do something in a background job, it's defined in a method on an active record object.
4
+
5
+ Zero explicit dependencies. (just respond to `id` and `find` like AR does)
6
+
7
+ ##Example
8
+
9
+ gem is called `async-jobs`
10
+
11
+ ```ruby
12
+ require 'async'
13
+ require 'async/resque'
14
+ Async.backend = Async::ResqueBackend
15
+
16
+ class Invoice < ActiveRecord::Base
17
+ def process(arg)
18
+ Async.run{ process_now(arg)}
19
+ end
20
+ def process_now(arg)
21
+ #actually do it
22
+ end
23
+ end
24
+
25
+ invoice.process 1
26
+ ```
27
+
28
+ Will enqueue a Resque job that runs `invoice.process_now 1`
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "async/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "async-jobs"
7
+ s.version = Async::VERSION
8
+ s.author = "Jacob"
9
+ s.email = "jacob@engineyard.com"
10
+ s.homepage = "https://github.com/engineyard/async"
11
+ s.summary = "abstraction over background job systems"
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.require_paths = ['lib']
16
+
17
+ end
@@ -0,0 +1,119 @@
1
+ class Async
2
+ class << self
3
+ attr_accessor :backend
4
+ end
5
+
6
+ class MethodCatcher
7
+ attr_reader :_method_name, :_args
8
+ def method_missing(method_name, *args)
9
+ @_method_name = method_name
10
+ @_args = args
11
+ end
12
+ end
13
+
14
+ def self.ensure_backend!
15
+ unless Async.backend
16
+ raise "Please configure the background processing system of choice by setting: Async.backend="
17
+ end
18
+ end
19
+
20
+ def self.run(&block)
21
+ ensure_backend!
22
+ receiver = block.binding.eval("self")
23
+ mc = MethodCatcher.new
24
+ mc.instance_eval(&block)
25
+ run_later self.to_s, receiver, mc._method_name, *mc._args
26
+ end
27
+
28
+ def self.run_later(job_class, receiver, method_name, *args)
29
+ if receiver.is_a?(Class)
30
+ receiver_class, receiver_id = receiver.to_s, nil
31
+ else
32
+ receiver_class, receiver_id = receiver.class.to_s, receiver.id
33
+ end
34
+ Async.backend.enqueue Async.backend.job_class, job_class, receiver_class, receiver_id, method_name, Job.transform_args(args)
35
+ end
36
+
37
+ def self.run_now(receiver, method_name, args)
38
+ Notifications.notify_job("run", receiver, method_name, args)
39
+ receiver.send(method_name, *args)
40
+ ensure
41
+ Notifications.notify_job("finish", receiver, method_name, args)
42
+ end
43
+
44
+ #TODO: test this
45
+ class Notifications
46
+ class << self
47
+ attr_accessor :handler
48
+ end
49
+ def self.notify_lock(thing, lock_name)
50
+ handler && handler.call(thing, {:lock_name => lock_name})
51
+ end
52
+ def self.notify_job(thing, receiver, method_name, args)
53
+ handler && handler.call(thing, {
54
+ :receiver => receiver,
55
+ :method_name => method_name.to_sym,
56
+ :args => args
57
+ })
58
+ end
59
+ end
60
+
61
+ #TODO: test this
62
+ class ErrorReporting
63
+ class << self
64
+ attr_accessor :handler
65
+ end
66
+ def self.notify_exception(e, job_args)
67
+ handler && handler.call(e, job_args)
68
+ end
69
+ end
70
+
71
+ class Job
72
+
73
+ def self.perform(wrapper, receiver_class_str, receiver_id, method, args)
74
+ receiver_class = constantize(receiver_class_str)
75
+ receiver = receiver_id ? receiver_class.find(receiver_id) : receiver_class
76
+ untransform_args = untransform_args(args)
77
+ constantize(wrapper).run_now(receiver, method, untransform_args)
78
+ rescue => e
79
+ ErrorReporting.notify_exception(e,
80
+ receiver_class_str: receiver_class_str, receiver_id: receiver_id, method: method, args: args)
81
+ end
82
+
83
+ def self.transform_args(args)
84
+ args.map do |x|
85
+ if x.class.respond_to?(:find)
86
+ {'_transform_arg' => true, 'class' => x.class.to_s, 'id' => x.id}
87
+ elsif x.is_a?(Array)
88
+ transform_args(x)
89
+ else
90
+ x
91
+ end
92
+ end
93
+ end
94
+
95
+ def self.untransform_args(args)
96
+ args.map do |x|
97
+ if x.is_a?(Hash) && x['_transform_arg']
98
+ constantize(x['class']).find(x['id'])
99
+ elsif x.is_a?(Array)
100
+ untransform_args(x)
101
+ else
102
+ x
103
+ end
104
+ end
105
+ end
106
+
107
+ private
108
+
109
+ def self.constantize(str)
110
+ if str.respond_to?(:constantize)
111
+ str.constantize
112
+ else
113
+ eval(str)
114
+ end
115
+ end
116
+
117
+ end
118
+
119
+ end
@@ -0,0 +1,141 @@
1
+ class Async
2
+ class << self
3
+ attr_accessor :redis, :lock_time
4
+ end
5
+
6
+ class Locked < Async
7
+
8
+ def self.run_now(receiver, method_name, args)
9
+ Notifications.notify_job("consider", receiver, method_name, args)
10
+ if Lock.is_lock_arg?(args.first)
11
+ lock_arg = args.shift
12
+ lock = Lock.claim(make_lock_name(receiver)) || Lock.create(make_lock_name(receiver))
13
+ else
14
+ lock = Lock.create(make_lock_name(receiver))
15
+ end
16
+ if lock
17
+ super
18
+ else
19
+ run_later(self.to_s, receiver, method_name, *args)
20
+ end
21
+ ensure
22
+ lock && lock.release
23
+ end
24
+
25
+ def self.run_later(job_class, receiver, method_name, *args)
26
+ if lock = Lock.pass_on(make_lock_name(receiver))
27
+ super(job_class, receiver, method_name, lock.as_job_arg, *args)
28
+ else
29
+ super
30
+ end
31
+ end
32
+
33
+ def self.make_lock_name(receiver)
34
+ if receiver.is_a?(Class)
35
+ Lock.make_name(receiver.to_s, nil)
36
+ else
37
+ Lock.make_name(receiver.class.to_s, receiver.id)
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ class Lock
44
+ def self.make_name(*names)
45
+ "lock:"+names.join(":")
46
+ end
47
+
48
+ def initialize(lock_name)
49
+ @lock_name = lock_name
50
+ @passed_on = false
51
+ end
52
+
53
+ def self.is_lock_arg?(arg)
54
+ arg.is_a?(Hash) && arg["_lock_arg"]
55
+ end
56
+
57
+ def as_job_arg
58
+ {"_lock_arg" => true, 'lock_name' => @lock_name}
59
+ end
60
+
61
+ def claim
62
+ Notifications.notify_lock("claim", @lock_name)
63
+ if redis.get(@lock_name) #still locked
64
+ refresh!
65
+ return true
66
+ else
67
+ lock
68
+ end
69
+ end
70
+
71
+ def lock
72
+ if redis.setnx(@lock_name, "locked")
73
+ refresh!
74
+ Notifications.notify_lock("lock", @lock_name)
75
+ return true
76
+ else
77
+ return false
78
+ end
79
+ end
80
+
81
+ def refresh!
82
+ redis.expire(@lock_name, Async::Locked.lock_time || 15)
83
+ end
84
+
85
+ def pass_on
86
+ if @passed_on
87
+ #already passed on, can't pass again
88
+ false
89
+ else
90
+ @passed_on = true
91
+ true
92
+ end
93
+ end
94
+
95
+ def release
96
+ if @passed_on
97
+ return false
98
+ end
99
+ redis.del(@lock_name)
100
+ Notifications.notify_lock("release", @lock_name)
101
+ Thread.current["Async::Lock.named"][@lock_name] = nil
102
+ return true
103
+ end
104
+
105
+ def redis
106
+ Async::Locked.redis
107
+ end
108
+
109
+ def self.thread_kill_lock(lock_name)
110
+ Thread.current["Async::Lock.named"] ||= {}
111
+ Thread.current["Async::Lock.named"][lock_name] = nil
112
+ end
113
+
114
+ def self.thread_save_lock(lock_name, lock)
115
+ Thread.current["Async::Lock.named"] ||= {}
116
+ Thread.current["Async::Lock.named"][lock_name] = lock
117
+ end
118
+
119
+ def self.thread_fetch_lock(lock_name)
120
+ Thread.current["Async::Lock.named"] ||= {}
121
+ Thread.current["Async::Lock.named"][lock_name]
122
+ end
123
+
124
+ def self.claim(lock_name)
125
+ lock = Lock.new(lock_name)
126
+ lock.claim && thread_save_lock(lock_name, lock) && lock
127
+ end
128
+
129
+ def self.pass_on(lock_name)
130
+ lock = thread_fetch_lock(lock_name)
131
+ lock && lock.pass_on && lock
132
+ end
133
+
134
+ def self.create(lock_name)
135
+ lock = Lock.new(lock_name)
136
+ lock.lock && thread_save_lock(lock_name, lock) && lock
137
+ end
138
+
139
+ end
140
+
141
+ end
@@ -0,0 +1,15 @@
1
+ class Async
2
+
3
+ class QuBackend
4
+
5
+ def self.enqueue(job_class, *args)
6
+ Qu.enqueue(job_class, *args)
7
+ end
8
+
9
+ def self.job_class
10
+ Async::Job
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,19 @@
1
+ class Async
2
+
3
+ class ResqueBackend
4
+
5
+ def self.enqueue(job_class, *args)
6
+ Resque.enqueue(job_class, *args)
7
+ end
8
+
9
+ def self.job_class
10
+ Async::ResqueBackend::Job
11
+ end
12
+
13
+ class Job < Async::Job
14
+ @queue = :default
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,25 @@
1
+ require 'sidekiq'
2
+ class Async
3
+
4
+ class SidekiqBackend
5
+
6
+ def self.enqueue(job_class, *args)
7
+ job_class.perform_async(*args)
8
+ end
9
+
10
+ def self.job_class
11
+ Async::SidekiqBackend::Job
12
+ end
13
+
14
+ class Job < Async::Job
15
+ include Sidekiq::Worker
16
+
17
+ def perform(*args)
18
+ self.class.perform(*args)
19
+ end
20
+
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,3 @@
1
+ class Async
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,121 @@
1
+ require 'async'
2
+ require 'async/qu'
3
+ require 'async/locked'
4
+ require 'qu'
5
+ require 'redis'
6
+ require 'shared/models'
7
+
8
+ require 'qu-immediate'
9
+ class PoppableQu < Qu::Backend::Immediate
10
+
11
+ def self.queue
12
+ @queue ||= []
13
+ end
14
+
15
+ def enqueue(payload)
16
+ PoppableQu.queue.unshift(payload)
17
+ end
18
+
19
+ end
20
+
21
+ describe Async::Locked do
22
+ before(:all) do
23
+ Async.backend = Async::QuBackend
24
+ Async::Locked.redis = Redis.new
25
+ end
26
+ before(:each) do
27
+ @qubackend = Qu.backend
28
+ Qu.backend = PoppableQu.new
29
+ end
30
+ after(:each) do
31
+ Qu.backend = @qubackend
32
+ end
33
+
34
+ it "works" do
35
+ Async::Locked.redis.flushdb
36
+
37
+ order_of_ops = []
38
+ Async::Notifications.handler = Proc.new do |name, hash|
39
+ # puts [name, (hash[:method_name] || hash[:lock_name]).to_s, hash[:args]].inspect
40
+ order_of_ops << [name, (hash[:method_name] || hash[:lock_name]).to_s]
41
+ end
42
+
43
+ Thread.current["Async::Lock.named"] = nil
44
+ y = Yard.new
45
+ y.save
46
+ y.do_all_the_work("front")
47
+ y.conflict
48
+
49
+ PoppableQu.queue.size.should eq 2
50
+ next_job = PoppableQu.queue.pop
51
+ next_job.args.should eq ["Async::Locked", "Yard", y.id, :now_do_all_the_work, ["front"]]
52
+
53
+ # puts ""
54
+ Thread.current["Async::Lock.named"] = nil
55
+ next_job.perform
56
+
57
+ PoppableQu.queue.size.should eq 3
58
+ next_job = PoppableQu.queue.pop
59
+ next_job.args.should eq ["Async::Locked", "Yard", 0, :now_conflict, []]
60
+
61
+ # puts ""
62
+ Thread.current["Async::Lock.named"] = nil
63
+ next_job.perform
64
+
65
+ PoppableQu.queue.size.should eq 3
66
+ next_job = PoppableQu.queue.pop
67
+ next_job.args.should eq ["Async::Locked", "Yard", y.id, :now_trim, [{"_lock_arg"=>true, "lock_name"=>"lock:Yard:0"}, "front"]]
68
+
69
+ # puts ""
70
+ Thread.current["Async::Lock.named"] = nil
71
+ next_job.perform
72
+
73
+ PoppableQu.queue.size.should eq 2
74
+ next_job = PoppableQu.queue.pop
75
+ next_job.args.should eq ["Async", "Yard", y.id, :now_mow, ["front"]]
76
+
77
+ # puts ""
78
+ Thread.current["Async::Lock.named"] = nil
79
+ next_job.perform
80
+
81
+ PoppableQu.queue.size.should eq 2
82
+ next_job = PoppableQu.queue.pop
83
+ next_job.args.should eq ["Async::Locked", "Yard", 0, :now_conflict, []]
84
+
85
+ # puts ""
86
+ Thread.current["Async::Lock.named"] = nil
87
+ next_job.perform
88
+
89
+ PoppableQu.queue.size.should eq 1
90
+ next_job = PoppableQu.queue.pop
91
+ next_job.args.should eq ["Async", "Yard", nil, :now_burn, []]
92
+
93
+ # puts ""
94
+ Thread.current["Async::Lock.named"] = nil
95
+ next_job.perform
96
+
97
+ PoppableQu.queue.size.should eq 0
98
+
99
+ order_of_ops.should eq [
100
+ ["consider", "now_do_all_the_work"],
101
+ ["lock", "lock:Yard:0"],
102
+ ["run", "now_do_all_the_work"],
103
+ ["finish", "now_do_all_the_work"],
104
+ ["consider", "now_conflict"],
105
+ ["consider", "now_trim"],
106
+ ["claim", "lock:Yard:0"],
107
+ ["run", "now_trim"],
108
+ ["finish", "now_trim"],
109
+ ["release", "lock:Yard:0"],
110
+ ["run", "now_mow"],
111
+ ["finish", "now_mow"],
112
+ ["consider", "now_conflict"],
113
+ ["lock", "lock:Yard:0"],
114
+ ["run", "now_conflict"],
115
+ ["finish", "now_conflict"],
116
+ ["release", "lock:Yard:0"],
117
+ ["run", "now_burn"],
118
+ ["finish", "now_burn"]]
119
+ end
120
+
121
+ end
@@ -0,0 +1,40 @@
1
+ require 'async'
2
+ require 'shared/models'
3
+
4
+ class TestBackend
5
+ def initialize
6
+ @jobs = []
7
+ end
8
+ def enqueue(job_class, *args)
9
+ @jobs << [job_class, args]
10
+ end
11
+ def run_all_jobs!
12
+ while(job = @jobs.pop)
13
+ job_class, args = job
14
+ job_class.perform(*args)
15
+ end
16
+ end
17
+ def job_class
18
+ Async::Job
19
+ end
20
+ end
21
+
22
+ describe "Async basics" do
23
+ before(:all) do
24
+ @test_backend = TestBackend.new
25
+ Async.backend = @test_backend
26
+ end
27
+
28
+ it "works" do
29
+ y = Yard.new
30
+ y.save
31
+ y.mowed.should be_nil
32
+ y.mow("front")
33
+
34
+ @test_backend.run_all_jobs!
35
+
36
+ y.reload
37
+ y.mowed.should eq "front"
38
+ end
39
+
40
+ end
@@ -0,0 +1,23 @@
1
+ require 'async'
2
+ require 'async/qu'
3
+ require 'shared/models'
4
+ require 'qu'
5
+ require 'qu-immediate'
6
+
7
+ describe "Async qu" do
8
+ before(:all) do
9
+ Qu.backend = Qu::Backend::Immediate.new
10
+ Async.backend = Async::QuBackend
11
+ end
12
+
13
+ it "works" do
14
+ y = Yard.new
15
+ y.save
16
+ y.mowed.should be_nil
17
+ y.mow("front")
18
+
19
+ y.reload
20
+ y.mowed.should eq "front"
21
+ end
22
+
23
+ end
@@ -0,0 +1,28 @@
1
+ require 'async'
2
+ require 'async/resque'
3
+ require 'shared/models'
4
+ require 'redis'
5
+ require 'resque'
6
+
7
+ describe "Async resque" do
8
+ before(:all) do
9
+ Resque.redis = Redis.new
10
+ Async.backend = Async::ResqueBackend
11
+ end
12
+
13
+ it "works" do
14
+ y = Yard.new
15
+ y.save
16
+ y.mowed.should be_nil
17
+ y.mow("front")
18
+
19
+ worker = Resque::Worker.new("*")
20
+ while job = worker.reserve
21
+ job.perform
22
+ end
23
+
24
+ y.reload
25
+ y.mowed.should eq "front"
26
+ end
27
+
28
+ end
@@ -0,0 +1,54 @@
1
+ require 'cubbyhole/base'
2
+ class Yard < Cubbyhole::Base
3
+
4
+ def self.backend
5
+ @backend ||= Hash.new
6
+ end
7
+
8
+ def self.find(id)
9
+ get(id)
10
+ end
11
+
12
+ def do_all_the_work(which)
13
+ Async::Locked.run{ now_do_all_the_work(which) }
14
+ end
15
+
16
+ def now_do_all_the_work(which)
17
+ # puts "do_all_the_work"
18
+ trim(which)
19
+ mow(which)
20
+ end
21
+
22
+ def trim(which)
23
+ Async::Locked.run{ now_trim(which) }
24
+ end
25
+
26
+ def now_trim(which)
27
+ # puts "trim #{which}"
28
+ end
29
+
30
+ def mow(which)
31
+ Async.run{ now_mow(which) }
32
+ end
33
+ def now_mow(which)
34
+ # puts "mow #{which}"
35
+ self.mowed = which
36
+ self.save
37
+ Yard.burn
38
+ end
39
+
40
+ def self.burn
41
+ Async.run{ now_burn }
42
+ end
43
+ def self.now_burn
44
+ # puts "burning..."
45
+ end
46
+
47
+ def conflict
48
+ Async::Locked.run{ now_conflict }
49
+ end
50
+ def now_conflict
51
+ # puts "conflict"
52
+ end
53
+
54
+ end
@@ -0,0 +1,23 @@
1
+ require 'async'
2
+ require 'async/sidekiq'
3
+ require 'shared/models'
4
+ require 'sidekiq/testing'
5
+
6
+ describe "Async sidekiq" do
7
+ before(:all) do
8
+ Async.backend = Async::SidekiqBackend
9
+ end
10
+
11
+ it "works" do
12
+ y = Yard.new
13
+ y.save
14
+ y.mowed.should be_nil
15
+ y.mow("front")
16
+
17
+ Async::SidekiqBackend::Job.drain
18
+
19
+ y.reload
20
+ y.mowed.should eq "front"
21
+ end
22
+
23
+ end
metadata ADDED
@@ -0,0 +1,67 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: async-jobs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Jacob
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-30 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: jacob@engineyard.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - ".gitignore"
20
+ - Gemfile
21
+ - Gemfile.lock
22
+ - MIT-LICENSE
23
+ - README.md
24
+ - async.gemspec
25
+ - lib/async.rb
26
+ - lib/async/locked.rb
27
+ - lib/async/qu.rb
28
+ - lib/async/resque.rb
29
+ - lib/async/sidekiq.rb
30
+ - lib/async/version.rb
31
+ - spec/async_and_lock_spec.rb
32
+ - spec/basics_spec.rb
33
+ - spec/qu_spec.rb
34
+ - spec/resque_spec.rb
35
+ - spec/shared/models.rb
36
+ - spec/sidekiq_spec.rb
37
+ homepage: https://github.com/engineyard/async
38
+ licenses: []
39
+ metadata: {}
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubyforge_project:
56
+ rubygems_version: 2.5.1
57
+ signing_key:
58
+ specification_version: 4
59
+ summary: abstraction over background job systems
60
+ test_files:
61
+ - spec/async_and_lock_spec.rb
62
+ - spec/basics_spec.rb
63
+ - spec/qu_spec.rb
64
+ - spec/resque_spec.rb
65
+ - spec/shared/models.rb
66
+ - spec/sidekiq_spec.rb
67
+ has_rdoc: