afterparty 0.0.21 → 0.1.0
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.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/.travis.yml +3 -1
- data/Gemfile +3 -1
- data/README.md +57 -13
- data/afterparty.gemspec +1 -0
- data/afterparty_test.sqlite3 +0 -0
- data/app/assets/javascripts/afterparty.js.coffee +14 -0
- data/app/assets/stylesheets/afterparty.css.sass +91 -0
- data/app/controllers/afterparty/dashboard_controller.rb +44 -0
- data/app/views/afterparty/dashboard/index.html.haml +85 -0
- data/config/routes.rb +9 -0
- data/lib/afterparty.rb +51 -7
- data/lib/afterparty/afterparty_job.rb +31 -0
- data/lib/afterparty/engine.rb +7 -0
- data/lib/afterparty/job_container.rb +36 -0
- data/lib/afterparty/jobs.rb +41 -0
- data/lib/afterparty/queue.rb +53 -0
- data/lib/afterparty/queue_helpers.rb +90 -15
- data/lib/afterparty/version.rb +1 -1
- data/lib/afterparty/worker.rb +46 -0
- data/lib/generators/afterparty_generator.rb +9 -0
- data/lib/generators/templates/initializer.rb +6 -0
- data/lib/generators/templates/jobs_migration.rb +21 -0
- data/lib/tasks/tasks.rake +25 -0
- data/spec/afterparty_job_spec.rb +17 -0
- data/spec/database.yml +3 -0
- data/spec/generators/afterparty_generator_spec.rb +10 -0
- data/spec/queue_functional_spec.rb +112 -0
- data/spec/queue_helpers_spec.rb +56 -0
- data/spec/schema.rb +14 -0
- data/spec/spec_helper.rb +15 -1
- metadata +44 -5
- data/lib/afterparty/redis_queue.rb +0 -57
- data/spec/redis_queue_spec.rb +0 -98
data/spec/database.yml
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe :afterparty do
|
3
|
+
it "works" do
|
4
|
+
subject.should generate(:copy_file, "jobs_migration.rb")
|
5
|
+
subject.should generate("config/initializers/afterparty.rb") do |content|
|
6
|
+
content.should include("Afterparty::Queue.new")
|
7
|
+
content.should include("queue.config_login do |username, password|")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe Afterparty::Queue do
|
3
|
+
before do
|
4
|
+
# require 'open-uri'
|
5
|
+
# uri = URI.parse("redis://localhost:6379")
|
6
|
+
# redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
|
7
|
+
# Afterparty.redis = redis
|
8
|
+
@q = Afterparty::TestQueue.new({sleep: 0.5, namespace: "master_test"})
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
@worker.stop
|
13
|
+
end
|
14
|
+
|
15
|
+
before :each do
|
16
|
+
@worker = Afterparty::Worker.new({sleep: 0.5})
|
17
|
+
# @worker.consume
|
18
|
+
@q.clear
|
19
|
+
@job_time = (ENV['AFTERPARTY_JOB_TIME'] || 5).to_i
|
20
|
+
@slow_job_time = (ENV['AFTERPARTY_SLOW_TIME'] || 7).to_i
|
21
|
+
end
|
22
|
+
|
23
|
+
it "pushes nil without errors" do
|
24
|
+
@q.push(nil)
|
25
|
+
@q.jobs.should eq([])
|
26
|
+
end
|
27
|
+
|
28
|
+
it "adds items to the queue" do
|
29
|
+
lambda {
|
30
|
+
@q.push(test_job)
|
31
|
+
}.should change{ @q.total_jobs_count }.by(1)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "executes the job" do
|
35
|
+
job = TestJob.new
|
36
|
+
@q.push(job)
|
37
|
+
lambda {
|
38
|
+
sleep(1)
|
39
|
+
@worker.consume_next
|
40
|
+
}.should change{ @q.total_jobs_count }.by(-1)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "removes items from the queue after running them" do
|
44
|
+
@q.push TestJob.new
|
45
|
+
sleep(1)
|
46
|
+
@worker.consume_next
|
47
|
+
@q.jobs.size.should == 0
|
48
|
+
end
|
49
|
+
|
50
|
+
it "doesn't execute jobs that execute in a while" do
|
51
|
+
job = TestJob.new
|
52
|
+
job.execute_at = Time.now + 200
|
53
|
+
@q.push job
|
54
|
+
lambda {
|
55
|
+
@worker.consume_next
|
56
|
+
}.should change{ @q.total_jobs_count }.by(0)
|
57
|
+
# @q.jobs.size.should eq(1)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "waits the correct amount of time to execute a job" do
|
61
|
+
job = TestJob.new
|
62
|
+
job.execute_at = Time.now + 4
|
63
|
+
@q.push(job)
|
64
|
+
sleep(1)
|
65
|
+
@q.jobs.size.should eq(1)
|
66
|
+
chill(@slow_job_time)
|
67
|
+
@worker.consume_next
|
68
|
+
@q.jobs.size.should eq(0)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "doesn't wait and execute the job synchronously when added" do
|
72
|
+
job = test_job 100
|
73
|
+
t = Time.now
|
74
|
+
@q.push(job)
|
75
|
+
(Time.now - t).should <= 1
|
76
|
+
end
|
77
|
+
|
78
|
+
it "executes jobs in the right order" do
|
79
|
+
late_job = test_job 60*10
|
80
|
+
early_job = test_job
|
81
|
+
@q.push(late_job)
|
82
|
+
@q.push(early_job)
|
83
|
+
sleep(1)
|
84
|
+
@worker.consume_next
|
85
|
+
(jobs = @q.jobs).size.should eq(1)
|
86
|
+
jobs[0].execute_at.should_not be(nil)
|
87
|
+
end
|
88
|
+
|
89
|
+
class ErrorJob
|
90
|
+
attr_accessor :execute_at
|
91
|
+
|
92
|
+
def run
|
93
|
+
raise "hello"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def complete
|
98
|
+
@q.completed_jobs
|
99
|
+
end
|
100
|
+
|
101
|
+
def error_job later=nil
|
102
|
+
job = ErrorJob.new
|
103
|
+
job.execute_at = DateTime.now + later if later
|
104
|
+
job
|
105
|
+
end
|
106
|
+
|
107
|
+
def chill seconds
|
108
|
+
t = Time.now
|
109
|
+
while Time.now < (t + seconds); end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe Afterparty::QueueHelpers do
|
3
|
+
before do
|
4
|
+
@q = Afterparty::Queue.new
|
5
|
+
end
|
6
|
+
|
7
|
+
before :each do
|
8
|
+
AfterpartyJob.destroy_all
|
9
|
+
end
|
10
|
+
|
11
|
+
it "destroys all jobs with with #clear" do
|
12
|
+
AfterpartyJob.make_with_job test_job(10)
|
13
|
+
AfterpartyJob.count.should == 1
|
14
|
+
@q.clear
|
15
|
+
AfterpartyJob.count.should == 0
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns incomplete jobs on #jobs" do
|
19
|
+
a = AfterpartyJob.make_with_job test_job(20)
|
20
|
+
b = AfterpartyJob.make_with_job test_job
|
21
|
+
@q.jobs.to_a.should == [b, a]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "doesn't return incomplete jobs on #valid_jobs" do
|
25
|
+
a = AfterpartyJob.make_with_job test_job(20)
|
26
|
+
b = AfterpartyJob.make_with_job test_job
|
27
|
+
@q.valid_jobs.to_a.should == [b]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns the next valid job" do
|
31
|
+
a = AfterpartyJob.make_with_job test_job(20)
|
32
|
+
b = AfterpartyJob.make_with_job test_job
|
33
|
+
c = AfterpartyJob.make_with_job test_job
|
34
|
+
@q.next_valid_job.should == b
|
35
|
+
end
|
36
|
+
|
37
|
+
it "correctly returns whether there are no valid jobs" do
|
38
|
+
AfterpartyJob.make_with_job test_job(20)
|
39
|
+
@q.jobs_empty?.should == true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "correctly returns the total number of incomplete jobs" do
|
43
|
+
AfterpartyJob.make_with_job test_job(20)
|
44
|
+
@q.total_jobs_count.should == 1
|
45
|
+
end
|
46
|
+
|
47
|
+
it "configures dashboard login successfully" do
|
48
|
+
expect{ @q.authenticate("user", "pass") }.to raise_exception
|
49
|
+
@q.config_login do |username, password|
|
50
|
+
username == "user" && password == "pass"
|
51
|
+
end
|
52
|
+
@q.authenticate("user","pass").should == true
|
53
|
+
@q.authenticate("userbad","pass").should == false
|
54
|
+
@q.authenticate("user","passbad").should == false
|
55
|
+
end
|
56
|
+
end
|
data/spec/schema.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
ActiveRecord::Schema.define version: 0 do
|
2
|
+
create_table "afterparty_jobs", force: true do |t|
|
3
|
+
t.text :job_dump
|
4
|
+
t.string :queue
|
5
|
+
t.datetime :execute_at
|
6
|
+
t.boolean :completed
|
7
|
+
t.boolean :has_error
|
8
|
+
t.text :error_message
|
9
|
+
t.text :error_backtrace
|
10
|
+
t.datetime :completed_at
|
11
|
+
|
12
|
+
t.datetime :created_at
|
13
|
+
end
|
14
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,8 +4,22 @@ require 'awesome_print'
|
|
4
4
|
require 'redis'
|
5
5
|
require 'afterparty' # and any other gems you need
|
6
6
|
require 'helpers'
|
7
|
+
require 'genspec'
|
7
8
|
|
8
9
|
RSpec.configure do |config|
|
9
10
|
# some (optional) config here
|
10
11
|
config.include Afterparty::QueueTestHelpers
|
11
|
-
end
|
12
|
+
end
|
13
|
+
|
14
|
+
database_yml = File.expand_path("../database.yml", __FILE__)
|
15
|
+
active_record_config = YAML.load_file(database_yml)
|
16
|
+
ActiveRecord::Base.configurations = active_record_config
|
17
|
+
ActiveRecord::Base.establish_connection("sqlite3")
|
18
|
+
|
19
|
+
load(File.dirname(__FILE__) + "/schema.rb")
|
20
|
+
|
21
|
+
def clean_database!
|
22
|
+
ActiveRecord::Base.connection.execute "DELETE FROM afterparty_jobs"
|
23
|
+
end
|
24
|
+
|
25
|
+
clean_database!
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: afterparty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hank Stoever
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
11
|
+
date: 2013-05-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ! '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: iconv
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -68,14 +82,34 @@ files:
|
|
68
82
|
- README.md
|
69
83
|
- Rakefile
|
70
84
|
- afterparty.gemspec
|
85
|
+
- afterparty_test.sqlite3
|
86
|
+
- app/assets/javascripts/afterparty.js.coffee
|
87
|
+
- app/assets/stylesheets/afterparty.css.sass
|
88
|
+
- app/controllers/afterparty/dashboard_controller.rb
|
89
|
+
- app/views/afterparty/dashboard/index.html.haml
|
90
|
+
- config/routes.rb
|
71
91
|
- dump.rdb
|
72
92
|
- lib/afterparty.rb
|
93
|
+
- lib/afterparty/afterparty_job.rb
|
94
|
+
- lib/afterparty/engine.rb
|
95
|
+
- lib/afterparty/job_container.rb
|
96
|
+
- lib/afterparty/jobs.rb
|
97
|
+
- lib/afterparty/queue.rb
|
73
98
|
- lib/afterparty/queue_helpers.rb
|
74
|
-
- lib/afterparty/redis_queue.rb
|
75
99
|
- lib/afterparty/threaded_queue_consumer.rb
|
76
100
|
- lib/afterparty/version.rb
|
101
|
+
- lib/afterparty/worker.rb
|
102
|
+
- lib/generators/afterparty_generator.rb
|
103
|
+
- lib/generators/templates/initializer.rb
|
104
|
+
- lib/generators/templates/jobs_migration.rb
|
105
|
+
- lib/tasks/tasks.rake
|
106
|
+
- spec/afterparty_job_spec.rb
|
107
|
+
- spec/database.yml
|
108
|
+
- spec/generators/afterparty_generator_spec.rb
|
77
109
|
- spec/helpers.rb
|
78
|
-
- spec/
|
110
|
+
- spec/queue_functional_spec.rb
|
111
|
+
- spec/queue_helpers_spec.rb
|
112
|
+
- spec/schema.rb
|
79
113
|
- spec/spec_helper.rb
|
80
114
|
homepage: ''
|
81
115
|
licenses:
|
@@ -102,7 +136,12 @@ signing_key:
|
|
102
136
|
specification_version: 4
|
103
137
|
summary: Rails 4 compatible queue with support for executing jobs later.
|
104
138
|
test_files:
|
139
|
+
- spec/afterparty_job_spec.rb
|
140
|
+
- spec/database.yml
|
141
|
+
- spec/generators/afterparty_generator_spec.rb
|
105
142
|
- spec/helpers.rb
|
106
|
-
- spec/
|
143
|
+
- spec/queue_functional_spec.rb
|
144
|
+
- spec/queue_helpers_spec.rb
|
145
|
+
- spec/schema.rb
|
107
146
|
- spec/spec_helper.rb
|
108
147
|
has_rdoc:
|
@@ -1,57 +0,0 @@
|
|
1
|
-
module Afterparty
|
2
|
-
class RedisQueue
|
3
|
-
attr_accessor :redis, :options, :temp_namespace, :consumer
|
4
|
-
include Afterparty::QueueHelpers
|
5
|
-
|
6
|
-
def initialize options={}, consumer_options={}
|
7
|
-
@consumer = ThreadedQueueConsumer.new(self, consumer_options).start
|
8
|
-
@options = options
|
9
|
-
@options[:namespace] ||= "default"
|
10
|
-
@options[:sleep] ||= 5
|
11
|
-
@mutex = Mutex.new
|
12
|
-
end
|
13
|
-
|
14
|
-
def push job
|
15
|
-
@mutex.synchronize do
|
16
|
-
return nil if job.nil?
|
17
|
-
async_redis_call{ redis_call :zadd, queue_time(job), Marshal.dump(job) }
|
18
|
-
@consumer.start unless @consumer.thread.alive?
|
19
|
-
@temp_namespace = nil
|
20
|
-
end
|
21
|
-
end
|
22
|
-
alias :<< :push
|
23
|
-
alias :eng :push
|
24
|
-
|
25
|
-
def pop
|
26
|
-
@mutex.synchronize do
|
27
|
-
while true do
|
28
|
-
if jobs_empty?
|
29
|
-
@consumer.shutdown
|
30
|
-
elsif !(_jobs = valid_jobs).empty?
|
31
|
-
job_dump = _jobs[0]
|
32
|
-
async_redis_call do
|
33
|
-
redis_call :zrem, job_dump
|
34
|
-
@temp_namespace = "completed"
|
35
|
-
redis_call :zadd, Time.now.to_i, job_dump
|
36
|
-
end
|
37
|
-
return Marshal.load(job_dump)
|
38
|
-
end
|
39
|
-
sleep(@options[:sleep])
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
class TestRedisQueue < RedisQueue
|
46
|
-
attr_accessor :completed_jobs
|
47
|
-
|
48
|
-
def initialize opts={}, consumer_opts={}
|
49
|
-
super
|
50
|
-
@completed_jobs = []
|
51
|
-
@exceptions = []
|
52
|
-
end
|
53
|
-
def handle_exception job, exception
|
54
|
-
@exceptions << [job, exception]
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
data/spec/redis_queue_spec.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
describe Afterparty::RedisQueue do
|
3
|
-
before do
|
4
|
-
require 'open-uri'
|
5
|
-
uri = URI.parse("redis://localhost:6379")
|
6
|
-
redis = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
|
7
|
-
Afterparty.redis = redis
|
8
|
-
@q = Afterparty::TestRedisQueue.new({sleep: 0.5})
|
9
|
-
end
|
10
|
-
|
11
|
-
before :each do
|
12
|
-
@q.completed_jobs.clear
|
13
|
-
@q.clear
|
14
|
-
Afterparty.redis.quit
|
15
|
-
@job_time = 10
|
16
|
-
end
|
17
|
-
|
18
|
-
it "pushes nil without errors" do
|
19
|
-
@q.push(nil)
|
20
|
-
@q.jobs.should eq([])
|
21
|
-
end
|
22
|
-
|
23
|
-
it "adds items to the queue" do
|
24
|
-
@q.push(test_job)
|
25
|
-
@q.total_jobs_count.should eq(1)
|
26
|
-
end
|
27
|
-
|
28
|
-
it "executes the job" do
|
29
|
-
job = TestJob.new
|
30
|
-
@q.push(job)
|
31
|
-
complete.size.should eq(0)
|
32
|
-
chill(@job_time)
|
33
|
-
complete.size.should eq(1)
|
34
|
-
end
|
35
|
-
|
36
|
-
it "removes items from the queue after running them" do
|
37
|
-
@q.push TestJob.new
|
38
|
-
chill(@job_time)
|
39
|
-
@q.jobs.should_not include(@job)
|
40
|
-
end
|
41
|
-
|
42
|
-
it "doesn't execute jobs that execute in a while" do
|
43
|
-
job = TestJob.new
|
44
|
-
job.execute_at = Time.now + 200
|
45
|
-
@q.push job
|
46
|
-
chill(@job_time)
|
47
|
-
complete.size.should eq(0)
|
48
|
-
end
|
49
|
-
|
50
|
-
it "waits the correct amount of time to execute a job" do
|
51
|
-
job = TestJob.new
|
52
|
-
job.execute_at = Time.now + 2
|
53
|
-
@q.push(job)
|
54
|
-
chill(50)
|
55
|
-
complete.size.should eq(1)
|
56
|
-
end
|
57
|
-
|
58
|
-
it "doesn't execute the job synchronously when added" do
|
59
|
-
job = test_job 100
|
60
|
-
t = Time.now
|
61
|
-
@q.push(job)
|
62
|
-
(Time.now - t).should <= 1
|
63
|
-
end
|
64
|
-
|
65
|
-
it "executes jobs in the right order" do
|
66
|
-
late_job = test_job 60*10
|
67
|
-
early_job = test_job
|
68
|
-
@q.push(late_job)
|
69
|
-
@q.push(early_job)
|
70
|
-
chill(@job_time)
|
71
|
-
complete.size.should eq(1)
|
72
|
-
complete[0].execute_at.should be(nil)
|
73
|
-
end
|
74
|
-
|
75
|
-
class ErrorJob
|
76
|
-
attr_accessor :execute_at
|
77
|
-
|
78
|
-
def run
|
79
|
-
raise "hello"
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def complete
|
84
|
-
@q.completed_jobs
|
85
|
-
end
|
86
|
-
|
87
|
-
def error_job later=nil
|
88
|
-
job = ErrorJob.new
|
89
|
-
job.execute_at = Time.now + later if later
|
90
|
-
job
|
91
|
-
end
|
92
|
-
|
93
|
-
def chill seconds
|
94
|
-
t = Time.now
|
95
|
-
while Time.now < (t + seconds); end
|
96
|
-
end
|
97
|
-
|
98
|
-
end
|