pq-wsm 0.0.1
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 +7 -0
- data/README.md +86 -0
- data/Rakefile +38 -0
- data/lib/generators/pc_queues/install_generator.rb +9 -0
- data/lib/generators/pc_queues/migration_generator.rb +15 -0
- data/lib/generators/pc_queues/templates/README +15 -0
- data/lib/generators/pc_queues/templates/initializer.rb +6 -0
- data/lib/generators/pc_queues/templates/migration.rb +36 -0
- data/lib/pc_queues.rb +43 -0
- data/lib/pc_queues/acts_as_enqueable.rb +31 -0
- data/lib/pc_queues/acts_as_queue_owner.rb +30 -0
- data/lib/pc_queues/priority_queue_item.rb +13 -0
- data/lib/pc_queues/queue.rb +312 -0
- data/lib/pc_queues/queue_item.rb +58 -0
- data/lib/pc_queues/queue_rule.rb +32 -0
- data/lib/pc_queues/queue_rule_set.rb +40 -0
- data/lib/pc_queues/queue_rules/boolean_queue_rule.rb +34 -0
- data/lib/pc_queues/queue_rules/numeric_queue_rule.rb +42 -0
- data/lib/pc_queues/queue_rules/sample_queue_rule.rb +36 -0
- data/lib/pc_queues/queue_rules/string_match_queue_rule.rb +44 -0
- data/lib/pc_queues/railtie.rb +10 -0
- data/lib/pc_queues/version.rb +3 -0
- data/lib/tasks/pc_queues_tasks.rake +4 -0
- data/spec/boolean_queue_rule_spec.rb +34 -0
- data/spec/numeric_queue_rule_spec.rb +123 -0
- data/spec/queue_spec.rb +494 -0
- data/spec/sample_queue_rule_spec.rb +34 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/string_match_rule_spec.rb +76 -0
- data/spec/support/active_record.rb +42 -0
- data/spec/support/application.rb +122 -0
- data/spec/support/queue_helpers.rb +16 -0
- data/spec/support/redis_helpers.rb +32 -0
- data/spec/support/time.rb +23 -0
- metadata +131 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3c57d60c589e660e163c69281336d7df78c743c4
|
4
|
+
data.tar.gz: 2db6479616a377cd2d0b5e38390aa35463ba4983
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 57a65396a0b836c2c4380c11276b0789af30807abd8523b83ae91b24690208eaeec17396ed6ed4a686893dbc82fe38686e1f3fbaaab4f5b421c368fd04500b38
|
7
|
+
data.tar.gz: 37770ac8c7cbee10c60d8fedc599d5f3c492f424614c439c941ee6936fb087eb3232a1ed1589d7b57082a77afab1384c37491c264fd7a1fe4e06c34a3199b27a
|
data/README.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
## PcQueues
|
2
|
+
|
3
|
+
A Queue Management Gem with Redis backing.
|
4
|
+
|
5
|
+
Copyright (c) ProctorCam Inc. 2014 All rights reserved
|
6
|
+
|
7
|
+
### Installation
|
8
|
+
|
9
|
+
Dependency: Rails, Database, PubNub
|
10
|
+
|
11
|
+
Add the following to your Gemfile
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'pc-queues', :git => 'git@gitlab.proctorcam.com:proctorcam-development/pc-queues', :branch => 'develop'
|
15
|
+
```
|
16
|
+
|
17
|
+
Run the install and migration generators
|
18
|
+
|
19
|
+
```bash
|
20
|
+
> rails g pc_queues:install
|
21
|
+
> rails g pc_queues:migration
|
22
|
+
> rake db:migrate
|
23
|
+
```
|
24
|
+
|
25
|
+
Update the initializer in config/initializers/pc_queues.rb to initialize the PubNub instance used.
|
26
|
+
|
27
|
+
That's it - you're done setting up.
|
28
|
+
|
29
|
+
### Getting Started
|
30
|
+
|
31
|
+
Once you've got the gem setup. You'll designate Models as Enqueable and as Queue owners. Classes that are Enqueueable
|
32
|
+
can be enqueued and dequeued from a Queue Classes that are Queue owners can have has_one and has_many relationships to
|
33
|
+
Queues.
|
34
|
+
|
35
|
+
Queues are setup for single table inheritance, so you can derive from Queue to handle Class specific behavior.
|
36
|
+
|
37
|
+
An ActiveRecordClass can be both a Queue owner and Enqueable.
|
38
|
+
|
39
|
+
#### Setting Up to be a Queue Owner
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
require 'pc_queues'
|
43
|
+
|
44
|
+
class MyQueue < PcQueues::Queue
|
45
|
+
end
|
46
|
+
|
47
|
+
class MyModel < ActiveRecord::Base
|
48
|
+
include ACTS_AS_QUEUE_OWNER
|
49
|
+
|
50
|
+
has_many_queues_as :my_queues
|
51
|
+
has_one_queue_as :fast_stuff, class_name: 'MyQueue'
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
#### Setting Up to be a Queue Item
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
require 'pc_queues'
|
59
|
+
|
60
|
+
class MyModel < ActiveRecord::Base
|
61
|
+
include ACTS_AS_ENQUEABLE
|
62
|
+
|
63
|
+
end
|
64
|
+
```
|
65
|
+
|
66
|
+
#### Queue Manipulation
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
model = MyModel.create attr1: value1
|
70
|
+
|
71
|
+
# has_one
|
72
|
+
model.create_fast_stuff attr1: value1
|
73
|
+
|
74
|
+
# has_many
|
75
|
+
model.my_queues.create attr1: value1
|
76
|
+
|
77
|
+
# Enqueue/Dequeue
|
78
|
+
model.fast_stuff.enqueue my_acts_as_enqueuable_object
|
79
|
+
|
80
|
+
my_acts_as_enqueuable_object = model.fast_stuff.dequeue
|
81
|
+
|
82
|
+
|
83
|
+
# Queue Length
|
84
|
+
length = model.fast_stuff.length
|
85
|
+
|
86
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'PcQueues'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
|
30
|
+
Rake::TestTask.new(:test) do |t|
|
31
|
+
t.libs << 'lib'
|
32
|
+
t.libs << 'test'
|
33
|
+
t.pattern = 'test/**/*_test.rb'
|
34
|
+
t.verbose = false
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
task :default => :test
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
class PcQueues::MigrationGenerator < ::Rails::Generators::Base
|
4
|
+
include Rails::Generators::Migration
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
6
|
+
desc "Installs PcQueues Gem migration file."
|
7
|
+
|
8
|
+
def install
|
9
|
+
migration_template 'migration.rb', 'db/migrate/create_pc_queues_tables.rb'
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.next_migration_number(dirname)
|
13
|
+
ActiveRecord::Generators::Base.next_migration_number(dirname)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
===============================================================================
|
2
|
+
|
3
|
+
There is a setup that will be needed before you use pc-queues.
|
4
|
+
|
5
|
+
1 - You'll need to edit config/initializers/pc_queues.rb to setup the PubNub instance
|
6
|
+
to use when publishing Queue activity and managing presence info.
|
7
|
+
|
8
|
+
2 - Run the migration generator and migrate
|
9
|
+
|
10
|
+
> rails g pc_queues:migration
|
11
|
+
> rake db:migrate
|
12
|
+
|
13
|
+
That's it, that's all. Enjoy!
|
14
|
+
|
15
|
+
===============================================================================
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class CreatePcQueuesTables < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :queues do |t|
|
4
|
+
t.string :name
|
5
|
+
t.string :type
|
6
|
+
t.boolean :is_in_cold_start, :default => false
|
7
|
+
t.integer :queue_owner_id
|
8
|
+
t.string :queue_owner_type
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table :queue_items do |t|
|
12
|
+
t.integer :position
|
13
|
+
t.integer :enqueued_time
|
14
|
+
t.integer :queue_id
|
15
|
+
t.integer :enqueable_id
|
16
|
+
t.string :enqueable_type
|
17
|
+
t.string :type
|
18
|
+
end
|
19
|
+
|
20
|
+
create_table :queue_rule_sets do |t|
|
21
|
+
t.boolean :is_any, :default => false
|
22
|
+
t.integer :queue_id
|
23
|
+
end
|
24
|
+
|
25
|
+
create_table :queue_rules do |t|
|
26
|
+
t.string :type
|
27
|
+
t.string :name
|
28
|
+
t.integer :numeric_value
|
29
|
+
t.string :string_value
|
30
|
+
t.integer :queue_rule_set_id
|
31
|
+
t.boolean :bool_value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
data/lib/pc_queues.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#
|
2
|
+
# This source file is part of project: PcQueues
|
3
|
+
#
|
4
|
+
# A Proctoring Workflow Platform
|
5
|
+
#
|
6
|
+
# Copyright (c) ProctorCam Inc. 2014 All rights reserved
|
7
|
+
#
|
8
|
+
|
9
|
+
module PcQueues
|
10
|
+
autoload :ActsAsQueueOwner, "pc_queues/acts_as_queue_owner"
|
11
|
+
autoload :ActsAsEnqueable, "pc_queues/acts_as_enqueable"
|
12
|
+
autoload :Queue, "pc_queues/queue"
|
13
|
+
autoload :QueueRule, "pc_queues/queue_rule"
|
14
|
+
autoload :PriorityQueueItem, "pc_queues/priority_queue_item"
|
15
|
+
autoload :QueueItem, "pc_queues/queue_item"
|
16
|
+
autoload :QueueRuleSet, "pc_queues/queue_rule_set"
|
17
|
+
|
18
|
+
module QueueRules
|
19
|
+
autoload :BooleanQueueRule, "pc_queues/queue_rules/boolean_queue_rule"
|
20
|
+
autoload :NumericQueueRule, "pc_queues/queue_rules/numeric_queue_rule"
|
21
|
+
autoload :SampleQueueRule, "pc_queues/queue_rules/sample_queue_rule"
|
22
|
+
autoload :StringMatchQueueRule, "pc_queues/queue_rules/string_match_queue_rule"
|
23
|
+
end
|
24
|
+
|
25
|
+
class << self
|
26
|
+
##
|
27
|
+
# Configuration for PcQueues - see config/initializers/pc_queues.rb for details
|
28
|
+
#
|
29
|
+
def config
|
30
|
+
yield self
|
31
|
+
end
|
32
|
+
|
33
|
+
def the_pubnub=(pubnub)
|
34
|
+
@@pubnub = pubnub
|
35
|
+
end
|
36
|
+
|
37
|
+
def the_pubnub
|
38
|
+
@@pubnub
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# This source file is part of project: PcQueues
|
3
|
+
#
|
4
|
+
# A Proctoring Workflow Platform
|
5
|
+
#
|
6
|
+
# Copyright (c) ProctorCam Inc. 2014 All rights reserved
|
7
|
+
#
|
8
|
+
require 'active_support'
|
9
|
+
|
10
|
+
module PcQueues
|
11
|
+
module ActsAsEnqueable
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
included do
|
15
|
+
acts_as_enqueuable
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def acts_as_enqueuable
|
20
|
+
# instances are enqueued with a polymorphic PcQueues::QueueItem instance
|
21
|
+
has_many :enqueued_with, :class_name => 'PcQueues::QueueItem', :as => :enqueable
|
22
|
+
|
23
|
+
# queues will return the PcQueues::Queue instances that
|
24
|
+
# this object is in.
|
25
|
+
has_many :queues, :through => :enqueued_with
|
26
|
+
|
27
|
+
before_destroy { |record| record.queues.each { |q| q.remove(record) } }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#
|
2
|
+
# This source file is part of project: PcQueues
|
3
|
+
#
|
4
|
+
# A Proctoring Workflow Platform
|
5
|
+
#
|
6
|
+
# Copyright (c) ProctorCam Inc. 2014 All rights reserved
|
7
|
+
#
|
8
|
+
require 'active_support'
|
9
|
+
|
10
|
+
module PcQueues
|
11
|
+
module ActsAsQueueOwner
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def has_many_queues_as(symbol, options = {})
|
16
|
+
klass = options[:class_name] or symbol.to_s.camelize.singularize
|
17
|
+
# has_many symbol, options.merge(:as => :queue_owner, :dependent => :destroy, :conditions => {:type => klass})
|
18
|
+
has_many symbol, -> {where(type: klass)}, options.merge(:as => :queue_owner, :dependent => :destroy) #==at :condtions is deprecated in rails 4, so replaced it with this
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_one_queue_as(symbol, options = {})
|
22
|
+
klass = options[:class_name] or symbol.to_s.camelize.singularize
|
23
|
+
has_one symbol, -> {where(type: klass)}, options.merge(:as => :queue_owner, :dependent => :destroy)
|
24
|
+
# has_one symbol, options.merge(:as => :queue_owner, :dependent => :destroy, :conditions => {:type => klass})
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
#
|
2
|
+
# This source file is part of project: PcQueues
|
3
|
+
#
|
4
|
+
# A Proctoring Workflow Platform
|
5
|
+
#
|
6
|
+
# Copyright (c) ProctorCam Inc. 2014 All rights reserved
|
7
|
+
#
|
8
|
+
module PcQueues
|
9
|
+
# PriorityQueueItems are a flavor of QueueItems that
|
10
|
+
# have higher priority.
|
11
|
+
class PriorityQueueItem < QueueItem
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,312 @@
|
|
1
|
+
#
|
2
|
+
# This source file is part of project: PcQueues
|
3
|
+
#
|
4
|
+
# A Proctoring Workflow Platform
|
5
|
+
#
|
6
|
+
# Copyright (c) ProctorCam Inc. 2014 All rights reserved
|
7
|
+
#
|
8
|
+
module PcQueues
|
9
|
+
# TODO: handle PubNub failures more gracefully
|
10
|
+
|
11
|
+
class Queue < ActiveRecord::Base
|
12
|
+
def self.accessible_attributes
|
13
|
+
[:name, :is_in_cold_start]
|
14
|
+
end
|
15
|
+
# attr_accessible :name, :is_in_cold_start
|
16
|
+
|
17
|
+
has_many :queue_items, dependent: :destroy, class_name: 'PcQueues::PriorityQueueItem'
|
18
|
+
has_many :priority_queue_items, dependent: :destroy, class_name: 'PcQueues::PriorityQueueItem'
|
19
|
+
has_many :queue_rule_sets, dependent: :destroy
|
20
|
+
|
21
|
+
belongs_to :queue_owner, :polymorphic => true
|
22
|
+
|
23
|
+
class_attribute :enqueue_callbacks, :dequeue_callbacks, :enqueable_type, :eager_load_relations
|
24
|
+
|
25
|
+
self.enqueue_callbacks = []
|
26
|
+
self.dequeue_callbacks = []
|
27
|
+
self.eager_load_relations = []
|
28
|
+
|
29
|
+
class << self
|
30
|
+
|
31
|
+
# An array of Queue Ids that have at least one client looking at them
|
32
|
+
def active_queue_ids
|
33
|
+
PubSub.proctors_for_class_instances(PcQueues::Queue).keys
|
34
|
+
end
|
35
|
+
|
36
|
+
# return Queue instances that have subscribers
|
37
|
+
def active_queues
|
38
|
+
Queue.find(active_queue_ids)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Publish statistics for all "active" queues, where
|
42
|
+
# the length is non-zero and there are active subscribers.
|
43
|
+
#
|
44
|
+
# Returns the active queues
|
45
|
+
def publish_active_queues
|
46
|
+
aq = active_queues
|
47
|
+
|
48
|
+
aq.each do |queue|
|
49
|
+
PubSub.publish(
|
50
|
+
:channel => "pc-queue-#{queue.id}",
|
51
|
+
:message => {
|
52
|
+
:qualifier => "stats",
|
53
|
+
:data => queue.stats
|
54
|
+
}
|
55
|
+
) { |data| }
|
56
|
+
end
|
57
|
+
|
58
|
+
aq
|
59
|
+
end
|
60
|
+
|
61
|
+
# Publish positions for all queue items in the queues provided
|
62
|
+
# if they have someone looking at them.
|
63
|
+
#
|
64
|
+
# The data published for each queue item is JSON-encoded:
|
65
|
+
# * position
|
66
|
+
# * estimated_time_left (in seconds)
|
67
|
+
#
|
68
|
+
def publish_positions(queues)
|
69
|
+
queues.each do |queue|
|
70
|
+
queue.publish_positions()
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Provide one or more callbacks to call before an item has been enqueued
|
75
|
+
#
|
76
|
+
# @param callbacks (symbol) the method name of the class that receives one
|
77
|
+
# parameters: the dequeued enqueable
|
78
|
+
def on_enqueue(*callbacks)
|
79
|
+
self.enqueue_callbacks = callbacks
|
80
|
+
end
|
81
|
+
|
82
|
+
# Provide one or more callbacks to call before an item has been dequeued
|
83
|
+
#
|
84
|
+
# @param callbacks (symbol) the method name of the class that receives one
|
85
|
+
# parameters: the dequeued enqueable
|
86
|
+
def on_dequeue(*callbacks)
|
87
|
+
self.dequeue_callbacks = callbacks
|
88
|
+
end
|
89
|
+
|
90
|
+
def enqueues(klass)
|
91
|
+
self.enqueable_type = klass
|
92
|
+
end
|
93
|
+
|
94
|
+
def eagerly_load(relations)
|
95
|
+
self.eager_load_relations = relations
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# A list of all the elements in this queue
|
102
|
+
def enqueables(options = {})
|
103
|
+
@enqueables ||= queue_items.includes(:enqueable).where(options).map{ |queue_item| queue_item.enqueable }
|
104
|
+
end
|
105
|
+
|
106
|
+
def length()
|
107
|
+
# Due to Single Table Inheritance queue_items.count will count all types.
|
108
|
+
# This will include priority queue items as well.
|
109
|
+
queue_items.count
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
def priority_length()
|
114
|
+
priority_queue_items.count
|
115
|
+
end
|
116
|
+
|
117
|
+
# The current queue_item advancement rate
|
118
|
+
# Returns 0 if there is no item.
|
119
|
+
def rate()
|
120
|
+
first = queue_items.first
|
121
|
+
first and first.rate
|
122
|
+
end
|
123
|
+
|
124
|
+
# The current estimated wait time in seconds for items
|
125
|
+
# added to the queue. Returns 0 if there are no items.
|
126
|
+
def wait_time()
|
127
|
+
first = queue_items.first
|
128
|
+
first and first.wait_time
|
129
|
+
end
|
130
|
+
|
131
|
+
# Enqueue an Object onto the Queue
|
132
|
+
def enqueue(obj)
|
133
|
+
with_lock do
|
134
|
+
# queue_item = obj.enqueued_with.create enqueued_time: Time.now.to_i, position: (length + 1), :queue => self
|
135
|
+
queue_item = queue_items.create enqueued_time: Time.now.to_i, position: (length + 1), enqueable: obj
|
136
|
+
|
137
|
+
enqueue_queue_item queue_item
|
138
|
+
end
|
139
|
+
|
140
|
+
obj
|
141
|
+
end
|
142
|
+
|
143
|
+
# Enqueue an object onto the queue with high priority
|
144
|
+
# -> it will get dequeued before any enqueables that were
|
145
|
+
# added with `enqueue`
|
146
|
+
def priority_enqueue(obj)
|
147
|
+
with_lock do
|
148
|
+
queue_item = priority_queue_items.create enqueued_time: Time.now.to_i, position: (priority_length + 1), enqueable: obj
|
149
|
+
|
150
|
+
enqueue_queue_item queue_item
|
151
|
+
end
|
152
|
+
|
153
|
+
obj
|
154
|
+
end
|
155
|
+
|
156
|
+
# enqueue an object if it passes the rules for this queue
|
157
|
+
def enqueue_if_passes(enqueable, *args)
|
158
|
+
enqueue(enqueable) if rules_pass(enqueable, *args)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Dequeue an Object from a Queue. The Object
|
162
|
+
# will no longer be in the Queue.
|
163
|
+
def dequeue()
|
164
|
+
obj = nil
|
165
|
+
|
166
|
+
while true do
|
167
|
+
begin
|
168
|
+
with_lock do
|
169
|
+
# Check priority_queue_items first, then queue_items
|
170
|
+
q_item = (priority_queue_items.first or queue_items.first)
|
171
|
+
|
172
|
+
return nil unless q_item
|
173
|
+
|
174
|
+
obj = q_item.enqueable
|
175
|
+
|
176
|
+
ActiveRecord::Associations::Preloader.new(obj, eager_load_relations).run
|
177
|
+
|
178
|
+
q_item.delete
|
179
|
+
end
|
180
|
+
rescue
|
181
|
+
# OK - Collided on a dequeued item, go try again.
|
182
|
+
next
|
183
|
+
end
|
184
|
+
# We've got an item, break
|
185
|
+
break
|
186
|
+
end
|
187
|
+
|
188
|
+
PubSub.publish(
|
189
|
+
:channel => "pc-queue-#{id}",
|
190
|
+
:message => [{
|
191
|
+
:qualifier => "dequeued",
|
192
|
+
:data => { :id => obj.id }
|
193
|
+
}, stats_message]
|
194
|
+
) { |data| }
|
195
|
+
|
196
|
+
dequeue_callbacks.each { |callback| send callback, obj }
|
197
|
+
|
198
|
+
obj
|
199
|
+
end
|
200
|
+
|
201
|
+
# Remove a specific item from the Queue
|
202
|
+
def remove(obj)
|
203
|
+
begin
|
204
|
+
with_lock do
|
205
|
+
q_item = queue_items.where(enqueable_id: obj.id).first
|
206
|
+
|
207
|
+
return nil unless q_item
|
208
|
+
|
209
|
+
q_item.destroy
|
210
|
+
end
|
211
|
+
rescue
|
212
|
+
# Someone else beat us to the punch - just leave
|
213
|
+
return nil
|
214
|
+
end
|
215
|
+
|
216
|
+
PubSub.publish(
|
217
|
+
:channel => "pc-queue-#{id}",
|
218
|
+
:message => [{
|
219
|
+
:qualifier => "removed",
|
220
|
+
:data => { :id => obj.id }
|
221
|
+
}, stats_message ]
|
222
|
+
) { |data| }
|
223
|
+
|
224
|
+
dequeue_callbacks.each { |callback| send callback, obj }
|
225
|
+
|
226
|
+
obj
|
227
|
+
end
|
228
|
+
|
229
|
+
# Determine if the rules for this queue pass
|
230
|
+
def rules_pass(enqueable, *args)
|
231
|
+
queue_rule_sets.includes(:queue_rules).all.each { |rule| return false unless rule.passes?(enqueable, *args) }
|
232
|
+
true
|
233
|
+
end
|
234
|
+
|
235
|
+
# Return the next object to be dequeued without dequeuing
|
236
|
+
def peek()
|
237
|
+
(item = queue_items.first)
|
238
|
+
item.cur_position = 1 unless item.nil?
|
239
|
+
item
|
240
|
+
end
|
241
|
+
|
242
|
+
# Current statistics for this queue
|
243
|
+
def stats
|
244
|
+
{
|
245
|
+
:length => length,
|
246
|
+
:rate => peek ? peek.rate : 0,
|
247
|
+
:longest_queue_wait => peek ? peek.wait_time : 0
|
248
|
+
}
|
249
|
+
end
|
250
|
+
|
251
|
+
# stats suitable for publishing
|
252
|
+
def stats_message
|
253
|
+
{
|
254
|
+
:qualifier => "stats",
|
255
|
+
:data => stats
|
256
|
+
}
|
257
|
+
end
|
258
|
+
|
259
|
+
def publish_stats
|
260
|
+
PcQueues::the_pubnub.publish(
|
261
|
+
:channel => "pc-queue-#{id}",
|
262
|
+
:message => stats_message
|
263
|
+
) { |data| }
|
264
|
+
end
|
265
|
+
|
266
|
+
# Publish positions for this queue; see class method for more detail
|
267
|
+
def publish_positions
|
268
|
+
positionize()
|
269
|
+
queue_items.each do |item|
|
270
|
+
PubSub.publish(
|
271
|
+
:channel => "pc-queue-item-#{item.enqueable.id}",
|
272
|
+
:message => {
|
273
|
+
:qualifier => "stats",
|
274
|
+
:data => item.stats
|
275
|
+
}
|
276
|
+
) { |data| }
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
protected
|
281
|
+
|
282
|
+
# DRY code for handling the common code between the regular and priority queues
|
283
|
+
def enqueue_queue_item(item)
|
284
|
+
# If validations fail, then the item is already in the queue.
|
285
|
+
return unless item.valid?
|
286
|
+
|
287
|
+
PubSub.publish(
|
288
|
+
:channel => "pc-queue-#{id}",
|
289
|
+
:message => [{
|
290
|
+
:qualifier => "enqueued",
|
291
|
+
:data => { :id => item.enqueable.id }
|
292
|
+
}, stats_message]
|
293
|
+
) { |data| }
|
294
|
+
|
295
|
+
enqueue_callbacks.each { |callback| send callback, item.enqueable }
|
296
|
+
item.enqueable
|
297
|
+
end
|
298
|
+
|
299
|
+
# update the current position for Right Now of each queue item
|
300
|
+
def positionize
|
301
|
+
q_items = queue_items.select {|item| item.instance_of? ::PcQueues::QueueItem}
|
302
|
+
p_queue_items = queue_items.select {|item| item.instance_of? ::PcQueues::PriorityQueueItem}
|
303
|
+
(p_queue_items | q_items).each_with_index { |item, ndx| item.cur_position = ndx + 1 }
|
304
|
+
end
|
305
|
+
|
306
|
+
# Convert an array of objects to a hash by ids
|
307
|
+
def objects_to_id_hash(objects)
|
308
|
+
Hash[objects.collect {|o| [o.id, o]}]
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
|
+
end
|