afterparty 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/hstove/afterparty.png?branch=master)](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
|