afterparty 0.0.2 → 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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -1
- data/README.md +4 -2
- data/afterparty.gemspec +1 -0
- data/app/assets/javascripts/afterparty.js.coffee +14 -0
- data/app/assets/stylesheets/afterparty.css.sass +85 -0
- data/app/controllers/afterparty/dashboard_controller.rb +20 -0
- data/app/views/afterparty/dashboard/index.html.haml +66 -0
- data/config/routes.rb +9 -0
- data/lib/afterparty.rb +49 -0
- data/lib/afterparty/engine.rb +7 -0
- data/lib/afterparty/job_container.rb +36 -0
- data/lib/afterparty/queue_helpers.rb +33 -4
- data/lib/afterparty/redis_queue.rb +16 -6
- data/lib/afterparty/version.rb +1 -1
- data/lib/afterparty/worker.rb +56 -0
- data/lib/tasks/tasks.rake +25 -0
- data/spec/redis_queue_spec.rb +23 -16
- metadata +25 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b61c1a12ac1be3fb98d8615c4126689032529792
|
4
|
+
data.tar.gz: 9ee9c0fd733e0d96133040e956a021e0f3f5c356
|
5
5
|
!binary "U0hBNTEy":
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d4e7ebafeff397b8aa751c60e8e1198a435701984be74d7f5275be86b55ac5cc41512db4846a42a81abecf57a5a56f9770554b39ef5fc9380570fb053e2e3f1
|
7
|
+
data.tar.gz: c744c87dc122d7901d6ebcc9b758740c6c563aa01ff8a802e23a7f49aa68d1b198bafe2460da9ba826efd3640cefde72e8e5f047d7139ad22a16f670c919dffe
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Afterparty
|
2
2
|
|
3
|
-
|
3
|
+
[](https://travis-ci.org/hstove/afterparty)
|
4
|
+
|
5
|
+
A Rails 4 compatible queue with support for executing jobs in the future and persistence with Redis.
|
4
6
|
|
5
7
|
## Installation
|
6
8
|
|
@@ -41,7 +43,7 @@ end
|
|
41
43
|
Then add it to the queue at any time.
|
42
44
|
|
43
45
|
~~~Ruby
|
44
|
-
Rails.queue << Job.new
|
46
|
+
Rails.configuration.queue << Job.new
|
45
47
|
~~~
|
46
48
|
|
47
49
|
If your job responds to an `execute_at` method, the queue will wait to process that job until the specified time.
|
data/afterparty.gemspec
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
$(document).ready ->
|
2
|
+
# $('.debug').click (e) ->
|
3
|
+
# $el = $(e.target)
|
4
|
+
# $tr = $el.parents('tr')
|
5
|
+
# $tr.next().toggle()
|
6
|
+
# $tr.toggleClass('debugged')
|
7
|
+
# false
|
8
|
+
$('.job-row').click (e) ->
|
9
|
+
$el = $(e.target)
|
10
|
+
return true if $el.hasClass('job-action')
|
11
|
+
$tr = $el.parents('tr')
|
12
|
+
$tr.next().toggle()
|
13
|
+
$tr.toggleClass('debugged')
|
14
|
+
false
|
@@ -0,0 +1,85 @@
|
|
1
|
+
body
|
2
|
+
:font-family helvetica
|
3
|
+
:background-color whitesmoke
|
4
|
+
:color lighten(black,30%)
|
5
|
+
:margin 0 20px
|
6
|
+
|
7
|
+
a:visited, a
|
8
|
+
:color rgb(96, 89, 180)
|
9
|
+
:text-decoration none
|
10
|
+
|
11
|
+
span
|
12
|
+
:font-size 12px
|
13
|
+
|
14
|
+
.job-table
|
15
|
+
:border-spacing 0
|
16
|
+
:max-width 100%
|
17
|
+
:margin 0px auto
|
18
|
+
thead tr:first-child
|
19
|
+
th
|
20
|
+
:border-width 1px 1px 1px 0
|
21
|
+
&:first-child
|
22
|
+
:border-width 1px 1px 1px 1px
|
23
|
+
th:first-child
|
24
|
+
:border-top-left-radius 2px
|
25
|
+
th:last-child
|
26
|
+
:border-top-right-radius 2px
|
27
|
+
tbody tr:last-child
|
28
|
+
td:first-child
|
29
|
+
:border-bottom-left-radius 2px
|
30
|
+
td:last-child
|
31
|
+
:border-bottom-right-radius 2px
|
32
|
+
tr
|
33
|
+
td, th
|
34
|
+
:border 1px solid #ccc
|
35
|
+
:border-width 0 1px 1px 0
|
36
|
+
:background-color lighten(whitesmoke, 5%)
|
37
|
+
:padding 12px 5px
|
38
|
+
:text-align left
|
39
|
+
:vertical-align middle
|
40
|
+
:word-wrap break-word
|
41
|
+
&:nth-child(2)
|
42
|
+
:width 70%
|
43
|
+
&:first-child
|
44
|
+
:border-width 0 1px 1px 1px
|
45
|
+
&:first-child, &:last-child
|
46
|
+
:width 15% !important
|
47
|
+
&.debugged
|
48
|
+
td
|
49
|
+
:background-color rgba(255,255,0,0.25)
|
50
|
+
&.job-row
|
51
|
+
:cursor pointer
|
52
|
+
h3
|
53
|
+
:margin 0
|
54
|
+
&:hover
|
55
|
+
td
|
56
|
+
:background-color rgba(0,0,0,0.15)
|
57
|
+
.description
|
58
|
+
:color white
|
59
|
+
.debug-row
|
60
|
+
:display none
|
61
|
+
:max-width 100%
|
62
|
+
td pre
|
63
|
+
:word-wrap break-word
|
64
|
+
:white-space pre-wrap
|
65
|
+
|
66
|
+
.distance-past, .distance-future
|
67
|
+
:font-size 12px
|
68
|
+
.distance-future
|
69
|
+
:color darken(rgb(0,255,0), 20%)
|
70
|
+
.distance-past
|
71
|
+
:color rgba(255,0,0,0.6)
|
72
|
+
|
73
|
+
.description
|
74
|
+
:font-size 12px
|
75
|
+
:color #bbb
|
76
|
+
:margin-left 10px
|
77
|
+
|
78
|
+
.job-action
|
79
|
+
:text-decoration underline
|
80
|
+
:font-size 12px
|
81
|
+
:margin 0 2px
|
82
|
+
|
83
|
+
.job_id
|
84
|
+
:color #bbb
|
85
|
+
:font-weight 700
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Afterparty
|
2
|
+
class DashboardController < ApplicationController
|
3
|
+
layout false
|
4
|
+
def index
|
5
|
+
@queues = Afterparty.queues
|
6
|
+
if params[:completed]
|
7
|
+
@jobs = queue.completed_with_scores
|
8
|
+
else
|
9
|
+
@jobs = queue.jobs_with_scores
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def queue
|
14
|
+
Rails.configuration.queue
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
!!!
|
2
|
+
%html
|
3
|
+
|
4
|
+
%head
|
5
|
+
%title== #{Rails.application.class.parent_name} Job Queue
|
6
|
+
%meta{"http-equiv"=>"Content-Type", :content=>"text/html; charset=utf-8"}
|
7
|
+
/ %meta{name: "viewport", content: "width=device-width, initial-scale=1.0"}
|
8
|
+
= stylesheet_link_tag "afterparty"
|
9
|
+
= javascript_include_tag "jquery", "afterparty"
|
10
|
+
= csrf_meta_tag
|
11
|
+
= favicon_link_tag
|
12
|
+
= yield(:head)
|
13
|
+
|
14
|
+
%body
|
15
|
+
%h1
|
16
|
+
Viewing
|
17
|
+
- if params[:completed]
|
18
|
+
= pluralize @jobs.size, "completed job"
|
19
|
+
%h3= link_to "View Job Queue", afterparty_engine.dashboard_path
|
20
|
+
- else
|
21
|
+
= pluralize @jobs.size, "job"
|
22
|
+
%h3= link_to "View Completed Jobs", afterparty_engine.dashboard_path(completed: true)
|
23
|
+
= @queues
|
24
|
+
%table.job-table
|
25
|
+
%thead
|
26
|
+
%tr
|
27
|
+
%th Execute At
|
28
|
+
/ %th Job
|
29
|
+
/ %th Actions
|
30
|
+
%tbody
|
31
|
+
- if @jobs.empty?
|
32
|
+
%tr
|
33
|
+
%td{colspan: 3}
|
34
|
+
%em No jobs to show...
|
35
|
+
- else
|
36
|
+
- @jobs.each do |job_container|
|
37
|
+
%tr.job-row
|
38
|
+
%td
|
39
|
+
%h3
|
40
|
+
- if job_container.job
|
41
|
+
= link_to job_container.job_class, "#", class: 'debug'
|
42
|
+
- if job_container.job.respond_to? :description
|
43
|
+
%span.description= job_container.job.description
|
44
|
+
- else
|
45
|
+
%em Error marshaling job
|
46
|
+
=# job_container.execute_at.strftime("%B %d, %Y at %l:%M %P")
|
47
|
+
- distance = time_ago_in_words(job_container.execute_at)
|
48
|
+
- if job_container.execute_at > Time.now
|
49
|
+
%span.distance-future= "in #{distance}"
|
50
|
+
- else
|
51
|
+
%span.distance-past= "#{distance} ago"
|
52
|
+
- if (_id = job_container.job_id) && (_queue = job_container.queue_name)
|
53
|
+
%span.job_id== ##{_id} #{_queue}
|
54
|
+
- unless params[:completed]
|
55
|
+
= link_to "run", afterparty_engine.run_job_path(job_id: _id, queue: _queue), class: 'job-action'
|
56
|
+
= link_to "delete", afterparty_engine.delete_job_path(job_id: _id, queue: _queue), class: 'job-action'
|
57
|
+
%tr.debug-row
|
58
|
+
%td
|
59
|
+
- if job_container.job
|
60
|
+
= debug job_container.job
|
61
|
+
- else
|
62
|
+
= job_container.raw_string
|
63
|
+
|
64
|
+
%p
|
65
|
+
Current Time:
|
66
|
+
= Time.now.strftime("%B %d, %Y at %l:%M %P")
|
data/config/routes.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Afterparty::Engine.routes.draw do
|
2
|
+
get "/" => "afterparty/dashboard#index", as: :dashboard
|
3
|
+
get "/run" => "afterparty/dashboard#run", as: :run_job
|
4
|
+
get "/delete" => "afterparty/dashboard#run", as: :delete_job
|
5
|
+
end
|
6
|
+
|
7
|
+
Rails.application.routes.draw do
|
8
|
+
mount Afterparty::Engine, at: "afterparty", as: "afterparty_engine"
|
9
|
+
end
|
data/lib/afterparty.rb
CHANGED
@@ -1,14 +1,63 @@
|
|
1
1
|
require 'logger'
|
2
2
|
require 'afterparty/queue_helpers'
|
3
3
|
require 'afterparty/redis_queue'
|
4
|
+
require 'redis'
|
4
5
|
Dir[File.expand_path('../afterparty/*', __FILE__)].each { |f| require f }
|
5
6
|
|
6
7
|
|
7
8
|
module Afterparty
|
9
|
+
@@redis = Redis.new
|
10
|
+
|
8
11
|
def self.redis
|
9
12
|
@@redis
|
10
13
|
end
|
11
14
|
def self.redis=(redis)
|
12
15
|
@@redis = redis
|
13
16
|
end
|
17
|
+
|
18
|
+
def self.clear namespace=:default
|
19
|
+
redis_call namespace, :del
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.redis_call namespace, command, *args
|
23
|
+
@@redis.send(command, redis_queue_name(namespace), *args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.redis_queue_name namespace=:default
|
27
|
+
"afterparty_#{namespace}_queue"
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.queues
|
31
|
+
@@redis.smembers "afterparty_queues"
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.add_queue name
|
35
|
+
@@redis.sadd "afterparty_queues", name
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.next_job_id namespace=:default
|
39
|
+
@@redis.incr "afterparty_#{namespace.to_s}_job_id"
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.load(raw)
|
43
|
+
begin
|
44
|
+
begin
|
45
|
+
job = Marshal.load(raw)
|
46
|
+
job = Marshal.load(job) if String === job
|
47
|
+
return job
|
48
|
+
rescue NameError => e
|
49
|
+
# lots of marshal load errors are because something that hasn't been
|
50
|
+
# required. recursively require on these errors
|
51
|
+
name = e.message.gsub("uninitialized constant ","").downcase
|
52
|
+
begin
|
53
|
+
require "#{name}"
|
54
|
+
return load(raw)
|
55
|
+
rescue LoadError
|
56
|
+
end
|
57
|
+
end
|
58
|
+
rescue
|
59
|
+
return nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
14
63
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'iconv'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
module Afterparty
|
5
|
+
class JobContainer
|
6
|
+
attr_accessor :job, :raw, :execute_at, :job_id, :queue_name
|
7
|
+
|
8
|
+
#intialized from redis's WITHSCORES function
|
9
|
+
def initialize _raw, timestamp
|
10
|
+
@execute_at = Time.at(timestamp)
|
11
|
+
begin
|
12
|
+
@job = Afterparty.load(_raw)
|
13
|
+
@job_id = job.afterparty_job_id if @job.respond_to? :afterparty_job_id
|
14
|
+
@queue_name = job.afterparty_queue if @job.respond_to? :afterparty_queue
|
15
|
+
rescue Exception => e
|
16
|
+
ap "Error during load: #{e.message}"
|
17
|
+
@job = nil
|
18
|
+
end
|
19
|
+
@raw = _raw
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def job_class
|
24
|
+
if @job
|
25
|
+
@job.class
|
26
|
+
else
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def raw_string
|
32
|
+
ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
|
33
|
+
ic.iconv(@raw.dup + ' ')[0..-2]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -4,8 +4,9 @@ module Afterparty
|
|
4
4
|
@temp_namespace = namespace
|
5
5
|
end
|
6
6
|
|
7
|
-
def redis_queue_name
|
8
|
-
|
7
|
+
def redis_queue_name
|
8
|
+
puts (a = Afterparty.redis_queue_name(@temp_namespace || @options[:namespace]))
|
9
|
+
a
|
9
10
|
end
|
10
11
|
|
11
12
|
def clear
|
@@ -13,7 +14,7 @@ module Afterparty
|
|
13
14
|
end
|
14
15
|
|
15
16
|
def redis_call command, *args
|
16
|
-
result = Afterparty.
|
17
|
+
result = Afterparty.redis_call (@temp_namespace || @options[:namespace]), command, *args
|
17
18
|
@temp_namespace = nil
|
18
19
|
result
|
19
20
|
end
|
@@ -31,13 +32,17 @@ module Afterparty
|
|
31
32
|
end
|
32
33
|
|
33
34
|
def jobs_with_scores
|
34
|
-
redis_call
|
35
|
+
hash_from_scores(redis_call(:zrange, 0, -1, {withscores: true}))
|
35
36
|
end
|
36
37
|
|
37
38
|
def valid_jobs
|
38
39
|
redis_call :zrangebyscore, 0, Time.now.to_i
|
39
40
|
end
|
40
41
|
|
42
|
+
def next_valid_job
|
43
|
+
valid_jobs.first
|
44
|
+
end
|
45
|
+
|
41
46
|
def jobs_empty?
|
42
47
|
count = total_jobs_count
|
43
48
|
# ap count
|
@@ -52,8 +57,32 @@ module Afterparty
|
|
52
57
|
@@redis
|
53
58
|
end
|
54
59
|
|
60
|
+
def last_completed
|
61
|
+
@temp_namespace = "completed"
|
62
|
+
redis_call(:zrange, -1, -1).first
|
63
|
+
end
|
64
|
+
|
65
|
+
def completed
|
66
|
+
@temp_namespace = "completed"
|
67
|
+
redis_call(:zrange, -20, -1).reverse
|
68
|
+
end
|
69
|
+
|
70
|
+
def completed_with_scores
|
71
|
+
@temp_namespace = "completed"
|
72
|
+
hash_from_scores(redis_call(:zrange, -20, -1, withscores: true)).reverse
|
73
|
+
end
|
74
|
+
|
75
|
+
|
55
76
|
private
|
56
77
|
|
78
|
+
def hash_from_scores raw
|
79
|
+
arr = []
|
80
|
+
raw.each do |group|
|
81
|
+
arr << Afterparty::JobContainer.new(group[0], group[1])
|
82
|
+
end
|
83
|
+
arr
|
84
|
+
end
|
85
|
+
|
57
86
|
# returns true if job has an :execute_at value
|
58
87
|
def job_valid? job
|
59
88
|
job.respond_to?(:execute_at) && !job.execute_at.nil?
|
@@ -4,9 +4,10 @@ module Afterparty
|
|
4
4
|
include Afterparty::QueueHelpers
|
5
5
|
|
6
6
|
def initialize options={}, consumer_options={}
|
7
|
-
@consumer = ThreadedQueueConsumer.new(self, consumer_options).start
|
7
|
+
# @consumer = ThreadedQueueConsumer.new(self, consumer_options).start
|
8
8
|
@options = options
|
9
9
|
@options[:namespace] ||= "default"
|
10
|
+
Afterparty.add_queue @options[:namespace]
|
10
11
|
@options[:sleep] ||= 5
|
11
12
|
@mutex = Mutex.new
|
12
13
|
end
|
@@ -14,8 +15,13 @@ module Afterparty
|
|
14
15
|
def push job
|
15
16
|
@mutex.synchronize do
|
16
17
|
return nil if job.nil?
|
18
|
+
job.class.module_eval do
|
19
|
+
attr_accessor :afterparty_job_id, :afterparty_queue
|
20
|
+
end
|
21
|
+
queue_name = @temp_namespace || @options[:namespace]
|
22
|
+
job.afterparty_queue = queue_name
|
23
|
+
job.afterparty_job_id = Afterparty.next_job_id queue_name
|
17
24
|
async_redis_call{ redis_call :zadd, queue_time(job), Marshal.dump(job) }
|
18
|
-
@consumer.start unless @consumer.thread.alive?
|
19
25
|
@temp_namespace = nil
|
20
26
|
end
|
21
27
|
end
|
@@ -25,16 +31,20 @@ module Afterparty
|
|
25
31
|
def pop
|
26
32
|
@mutex.synchronize do
|
27
33
|
while true do
|
28
|
-
if
|
29
|
-
@consumer.shutdown
|
30
|
-
elsif !(_jobs = valid_jobs).empty?
|
34
|
+
if !(_jobs = valid_jobs).empty?
|
31
35
|
job_dump = _jobs[0]
|
32
36
|
async_redis_call do
|
33
37
|
redis_call :zrem, job_dump
|
34
38
|
@temp_namespace = "completed"
|
35
39
|
redis_call :zadd, Time.now.to_i, job_dump
|
36
40
|
end
|
37
|
-
|
41
|
+
begin
|
42
|
+
return Marshal.load(job_dump)
|
43
|
+
rescue ArgumentException => e
|
44
|
+
puts "You encountered an argument exception while deserializing a job."
|
45
|
+
puts "Message: #{e.message}"
|
46
|
+
raise e
|
47
|
+
end
|
38
48
|
end
|
39
49
|
sleep(@options[:sleep])
|
40
50
|
end
|
data/lib/afterparty/version.rb
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Afterparty
|
2
|
+
class Worker
|
3
|
+
include QueueHelpers
|
4
|
+
|
5
|
+
def initialize options = {}
|
6
|
+
@options = options
|
7
|
+
@options[:adapter] ||= :redis
|
8
|
+
@options[:namespace] ||= :default
|
9
|
+
@options[:sleep] ||= 10
|
10
|
+
@options[:logger] ||= Logger.new($stderr)
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def consume
|
15
|
+
@stopped = false
|
16
|
+
# puts "starting worker with namespace [#{@options[:namespace]}]."
|
17
|
+
@thread = Thread.new {
|
18
|
+
consume_sync
|
19
|
+
}
|
20
|
+
@thread
|
21
|
+
end
|
22
|
+
|
23
|
+
def consume_sync
|
24
|
+
while !@stopped
|
25
|
+
job = next_valid_job
|
26
|
+
if job
|
27
|
+
async_redis_call do
|
28
|
+
@temp_namespace = "completed"
|
29
|
+
redis_call :zadd, Time.now.to_i, Marshal.dump(job)
|
30
|
+
redis_call :zrem, job
|
31
|
+
end
|
32
|
+
run job
|
33
|
+
else
|
34
|
+
sleep(@options[:sleep])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def stop
|
40
|
+
@stopped = true
|
41
|
+
@thread.join(0)
|
42
|
+
end
|
43
|
+
|
44
|
+
def run(job)
|
45
|
+
fork do
|
46
|
+
Marshal.load(job).run
|
47
|
+
end
|
48
|
+
rescue Exception => exception
|
49
|
+
handle_exception job, exception
|
50
|
+
end
|
51
|
+
|
52
|
+
def handle_exception(job, exception)
|
53
|
+
@options[:logger].error "Job Error: #{job.inspect}\n#{exception.message}\n#{exception.backtrace.join("\n")}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
namespace :jobs do
|
2
|
+
require 'mail'
|
3
|
+
|
4
|
+
desc "Start a new worker"
|
5
|
+
task work: :environment do
|
6
|
+
worker = Afterparty::Worker.new
|
7
|
+
worker.consume_sync
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Clear all jobs"
|
11
|
+
task clear: :environment do
|
12
|
+
Rails.configuration.queue.clear
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "List Jobs"
|
16
|
+
task list: :environment do
|
17
|
+
jobs = Rails.configuration.queue.jobs_with_scores
|
18
|
+
puts "#{jobs.values.size} total jobs."
|
19
|
+
jobs.each do |time, job|
|
20
|
+
puts time
|
21
|
+
puts job
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
data/spec/redis_queue_spec.rb
CHANGED
@@ -8,10 +8,16 @@ describe Afterparty::RedisQueue do
|
|
8
8
|
@q = Afterparty::TestRedisQueue.new({sleep: 0.5})
|
9
9
|
end
|
10
10
|
|
11
|
+
after do
|
12
|
+
@worker.stop
|
13
|
+
end
|
14
|
+
|
11
15
|
before :each do
|
12
|
-
@
|
16
|
+
@worker = Afterparty::Worker.new({sleep: 0.5})
|
17
|
+
@worker.consume
|
13
18
|
@q.clear
|
14
|
-
|
19
|
+
@job_time = (ENV['AFTERPARTY_JOB_TIME'] || 3).to_i
|
20
|
+
@slow_job_time = (ENV['AFTERPARTY_SLOW_TIME'] || 10).to_i
|
15
21
|
end
|
16
22
|
|
17
23
|
it "pushes nil without errors" do
|
@@ -27,34 +33,35 @@ describe Afterparty::RedisQueue do
|
|
27
33
|
it "executes the job" do
|
28
34
|
job = TestJob.new
|
29
35
|
@q.push(job)
|
30
|
-
|
31
|
-
chill(
|
32
|
-
|
36
|
+
@q.jobs.size.should eq(1)
|
37
|
+
chill(@job_time)
|
38
|
+
@q.jobs.size.should eq(0)
|
33
39
|
end
|
34
40
|
|
35
41
|
it "removes items from the queue after running them" do
|
36
42
|
@q.push TestJob.new
|
37
|
-
chill(
|
38
|
-
@q.jobs.
|
43
|
+
chill(@job_time)
|
44
|
+
@q.jobs.size.should == 0
|
39
45
|
end
|
40
46
|
|
41
47
|
it "doesn't execute jobs that execute in a while" do
|
42
48
|
job = TestJob.new
|
43
49
|
job.execute_at = Time.now + 200
|
44
50
|
@q.push job
|
45
|
-
chill(
|
46
|
-
|
51
|
+
chill(@job_time)
|
52
|
+
@q.jobs.size.should eq(1)
|
47
53
|
end
|
48
54
|
|
49
55
|
it "waits the correct amount of time to execute a job" do
|
50
56
|
job = TestJob.new
|
51
|
-
job.execute_at = Time.now +
|
57
|
+
job.execute_at = Time.now + 5
|
52
58
|
@q.push(job)
|
53
|
-
|
54
|
-
|
59
|
+
@q.jobs.size.should eq(1)
|
60
|
+
chill(@slow_job_time)
|
61
|
+
@q.jobs.size.should eq(0)
|
55
62
|
end
|
56
63
|
|
57
|
-
it "doesn't execute the job synchronously when added" do
|
64
|
+
it "doesn't wait and execute the job synchronously when added" do
|
58
65
|
job = test_job 100
|
59
66
|
t = Time.now
|
60
67
|
@q.push(job)
|
@@ -66,9 +73,9 @@ describe Afterparty::RedisQueue do
|
|
66
73
|
early_job = test_job
|
67
74
|
@q.push(late_job)
|
68
75
|
@q.push(early_job)
|
69
|
-
chill(
|
70
|
-
|
71
|
-
|
76
|
+
chill(@job_time)
|
77
|
+
(jobs = @q.jobs).size.should eq(1)
|
78
|
+
jobs[0].execute_at.should_not be(nil)
|
72
79
|
end
|
73
80
|
|
74
81
|
class ErrorJob
|
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.0.3
|
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-15 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,12 +82,21 @@ files:
|
|
68
82
|
- README.md
|
69
83
|
- Rakefile
|
70
84
|
- afterparty.gemspec
|
85
|
+
- app/assets/javascripts/afterparty.js.coffee
|
86
|
+
- app/assets/stylesheets/afterparty.css.sass
|
87
|
+
- app/controllers/afterparty/dashboard_controller.rb
|
88
|
+
- app/views/afterparty/dashboard/index.html.haml
|
89
|
+
- config/routes.rb
|
71
90
|
- dump.rdb
|
72
91
|
- lib/afterparty.rb
|
92
|
+
- lib/afterparty/engine.rb
|
93
|
+
- lib/afterparty/job_container.rb
|
73
94
|
- lib/afterparty/queue_helpers.rb
|
74
95
|
- lib/afterparty/redis_queue.rb
|
75
96
|
- lib/afterparty/threaded_queue_consumer.rb
|
76
97
|
- lib/afterparty/version.rb
|
98
|
+
- lib/afterparty/worker.rb
|
99
|
+
- lib/tasks/tasks.rake
|
77
100
|
- spec/helpers.rb
|
78
101
|
- spec/redis_queue_spec.rb
|
79
102
|
- spec/spec_helper.rb
|