mrflip-edamame 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +8 -0
- data/.gitignore +31 -0
- data/LICENSE.textile +21 -0
- data/README.textile +178 -0
- data/Rakefile +75 -0
- data/VERSION +1 -0
- data/app/edamame_san/config.ru +4 -0
- data/app/edamame_san/config.yml +17 -0
- data/app/edamame_san/config/.gitignore +1 -0
- data/app/edamame_san/edamame_san.rb +71 -0
- data/app/edamame_san/public/favicon.ico +0 -0
- data/app/edamame_san/public/images/edamame_logo.icns +0 -0
- data/app/edamame_san/public/images/edamame_logo.ico +0 -0
- data/app/edamame_san/public/images/edamame_logo.png +0 -0
- data/app/edamame_san/public/images/edamame_logo_2.icns +0 -0
- data/app/edamame_san/public/javascripts/application.js +8 -0
- data/app/edamame_san/public/javascripts/jquery/jquery-ui.js +8694 -0
- data/app/edamame_san/public/javascripts/jquery/jquery.js +4376 -0
- data/app/edamame_san/public/stylesheets/application.css +32 -0
- data/app/edamame_san/public/stylesheets/layout.css +88 -0
- data/app/edamame_san/views/layout.haml +13 -0
- data/app/edamame_san/views/load.haml +37 -0
- data/app/edamame_san/views/root.haml +25 -0
- data/bin/edamame-ps +2 -0
- data/bin/empty_all.rb +15 -0
- data/bin/stats.rb +13 -0
- data/bin/sync.rb +15 -0
- data/bin/test_run.rb +14 -0
- data/edamame.gemspec +110 -0
- data/lib/edamame.rb +193 -0
- data/lib/edamame/job.rb +134 -0
- data/lib/edamame/queue.rb +6 -0
- data/lib/edamame/queue/beanstalk.rb +132 -0
- data/lib/edamame/rescheduled.rb +89 -0
- data/lib/edamame/scheduling.rb +69 -0
- data/lib/edamame/store.rb +8 -0
- data/lib/edamame/store/base.rb +62 -0
- data/lib/edamame/store/tyrant_store.rb +50 -0
- data/lib/methods.txt +94 -0
- data/spec/edamame_spec.rb +7 -0
- data/spec/spec_helper.rb +9 -0
- data/utils/god/README-god.textile +54 -0
- data/utils/god/beanstalkd_god.rb +34 -0
- data/utils/god/edamame.god +30 -0
- data/utils/god/god-etc-init-dot-d-example +40 -0
- data/utils/god/god_email.rb +45 -0
- data/utils/god/god_process.rb +140 -0
- data/utils/god/god_site_config.rb +4 -0
- data/utils/god/sinatra_god.rb +36 -0
- data/utils/god/tyrant_god.rb +67 -0
- data/utils/simulation/Add Percent Variation.vi +0 -0
- data/utils/simulation/Harmonic Average.vi +0 -0
- data/utils/simulation/Rescheduling Simulation.aliases +3 -0
- data/utils/simulation/Rescheduling Simulation.lvlps +3 -0
- data/utils/simulation/Rescheduling Simulation.lvproj +22 -0
- data/utils/simulation/Rescheduling.vi +0 -0
- data/utils/simulation/Weighted Average.vi +0 -0
- metadata +135 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
/* ===========================================================================
|
2
|
+
Default styling for the upload bar
|
3
|
+
*/
|
4
|
+
|
5
|
+
body { margin: 0px ; }
|
6
|
+
|
7
|
+
.bar {
|
8
|
+
width: 300px;
|
9
|
+
}
|
10
|
+
#progress {
|
11
|
+
border: 1px solid #222;
|
12
|
+
display: block;
|
13
|
+
float: left;
|
14
|
+
margin-right: 0.25em;
|
15
|
+
}
|
16
|
+
#progressbar {
|
17
|
+
width: 0px;
|
18
|
+
height: 24px;
|
19
|
+
}
|
20
|
+
|
21
|
+
#progress { background: #eee; }
|
22
|
+
#progress #progressbar { background: #bbf; }
|
23
|
+
#progress.working { background: #eef; }
|
24
|
+
#progress.success #progressbar { background: #cfd; }
|
25
|
+
#progress.error { background: #fcc; }
|
26
|
+
#progress.error #progressbar { background: #fcd; }
|
27
|
+
|
28
|
+
iframe.yuploader {
|
29
|
+
border: 0px none white;
|
30
|
+
margin: 0px;
|
31
|
+
padding: 0px;
|
32
|
+
}
|
@@ -0,0 +1,88 @@
|
|
1
|
+
|
2
|
+
/*
|
3
|
+
Page layout
|
4
|
+
*/
|
5
|
+
|
6
|
+
body {
|
7
|
+
background-color: #4B7399;
|
8
|
+
font-family: Verdana, Helvetica, Arial;
|
9
|
+
font-size: 14px;
|
10
|
+
padding: 0;
|
11
|
+
margin: 0;
|
12
|
+
}
|
13
|
+
|
14
|
+
a img {
|
15
|
+
border: none;
|
16
|
+
}
|
17
|
+
|
18
|
+
a {
|
19
|
+
color: #0000FF;
|
20
|
+
}
|
21
|
+
|
22
|
+
.clear {
|
23
|
+
clear: both;
|
24
|
+
height: 0;
|
25
|
+
overflow: hidden;
|
26
|
+
}
|
27
|
+
|
28
|
+
#container {
|
29
|
+
width: 75%;
|
30
|
+
margin: 0 auto;
|
31
|
+
background-color: #FFF;
|
32
|
+
padding: 20px 40px;
|
33
|
+
border: solid 1px black;
|
34
|
+
margin-top: 20px;
|
35
|
+
}
|
36
|
+
|
37
|
+
#flash_notice, #flash_error {
|
38
|
+
padding: 5px 8px;
|
39
|
+
margin: 10px 0;
|
40
|
+
}
|
41
|
+
|
42
|
+
#flash_notice {
|
43
|
+
background-color: #CFC;
|
44
|
+
border: solid 1px #6C6;
|
45
|
+
}
|
46
|
+
|
47
|
+
#flash_error {
|
48
|
+
background-color: #FCC;
|
49
|
+
border: solid 1px #C66;
|
50
|
+
}
|
51
|
+
|
52
|
+
.fieldWithErrors {
|
53
|
+
display: inline;
|
54
|
+
}
|
55
|
+
|
56
|
+
#errorExplanation {
|
57
|
+
width: 400px;
|
58
|
+
border: 2px solid #CF0000;
|
59
|
+
padding: 0px;
|
60
|
+
padding-bottom: 12px;
|
61
|
+
margin-bottom: 20px;
|
62
|
+
background-color: #f0f0f0;
|
63
|
+
}
|
64
|
+
|
65
|
+
#errorExplanation h2 {
|
66
|
+
text-align: left;
|
67
|
+
font-weight: bold;
|
68
|
+
padding: 5px 5px 5px 15px;
|
69
|
+
font-size: 12px;
|
70
|
+
margin: 0;
|
71
|
+
background-color: #c00;
|
72
|
+
color: #fff;
|
73
|
+
}
|
74
|
+
|
75
|
+
#errorExplanation p {
|
76
|
+
color: #333;
|
77
|
+
margin-bottom: 0;
|
78
|
+
padding: 8px;
|
79
|
+
}
|
80
|
+
|
81
|
+
#errorExplanation ul {
|
82
|
+
margin: 2px 24px;
|
83
|
+
}
|
84
|
+
|
85
|
+
#errorExplanation ul li {
|
86
|
+
font-size: 12px;
|
87
|
+
list-style: disc;
|
88
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
!!! XML
|
2
|
+
!!! Strict
|
3
|
+
%html{ "xml:lang" => "en", :lang => "en", :xmlns => "http://www.w3.org/1999/xhtml" }
|
4
|
+
%head
|
5
|
+
%link{ :href => "/stylesheets/application.css", :rel => "stylesheet", :type => "text/css" }
|
6
|
+
%link{ :href => "/favicon.ico", :rel => "shortcut icon", :type => "image/x-icon" }
|
7
|
+
|
8
|
+
%body
|
9
|
+
#container
|
10
|
+
=yield
|
11
|
+
|
12
|
+
-# %script{ :type => "text/javascript", :src => "http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" }
|
13
|
+
-# %script{ :type => "text/javascript", :src => "http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js" }
|
@@ -0,0 +1,37 @@
|
|
1
|
+
%style{ :type => 'text/css' }
|
2
|
+
@import url('/stylesheets/layout.css');
|
3
|
+
|
4
|
+
%p
|
5
|
+
|
6
|
+
Jobs in the edamame job store:
|
7
|
+
|
8
|
+
|
9
|
+
%table
|
10
|
+
%tr
|
11
|
+
%th query_term
|
12
|
+
%th priority
|
13
|
+
%th prev_items
|
14
|
+
%th prev_rate
|
15
|
+
%th prev_span_min
|
16
|
+
%th prev_span_max
|
17
|
+
- @dest_store.each_as(Edamame::Job) do |key, obj|
|
18
|
+
%tr
|
19
|
+
%td=h key.inspect
|
20
|
+
%td=h obj.inspect
|
21
|
+
%td=h obj.key
|
22
|
+
-# %td=h obj[:query_term]
|
23
|
+
-# %td=h obj[:priority]
|
24
|
+
-# %td=h obj[:prev_items]
|
25
|
+
-# %td=h obj[:prev_rate]
|
26
|
+
-# %td=h obj[:prev_span_min]
|
27
|
+
-# %td=h obj[:prev_span_max]
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
%style{ :type => 'text/css' }
|
2
|
+
@import url('/stylesheets/layout.css');
|
3
|
+
|
4
|
+
%p
|
5
|
+
|
6
|
+
Jobs in the edamame job store:
|
7
|
+
|
8
|
+
|
9
|
+
%table
|
10
|
+
%tr
|
11
|
+
%th query_term
|
12
|
+
%th priority
|
13
|
+
%th prev_items
|
14
|
+
%th prev_rate
|
15
|
+
%th prev_span_min
|
16
|
+
%th prev_span_max
|
17
|
+
- @store.each_as(Wuclan::Domains::Twitter::Scrape::TwitterSearchJob) do |key, obj|
|
18
|
+
%tr
|
19
|
+
-# %td=h key.inspect
|
20
|
+
%td=h obj[:query_term]
|
21
|
+
%td=h obj[:priority]
|
22
|
+
%td=h obj[:prev_items]
|
23
|
+
%td=h obj[:prev_rate]
|
24
|
+
%td=h obj[:prev_span_min]
|
25
|
+
%td=h obj[:prev_span_max]
|
data/bin/edamame-ps
ADDED
data/bin/empty_all.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$: << File.dirname(__FILE__)+'/../../lib'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'edamame'
|
5
|
+
require 'monkeyshines/monitor'
|
6
|
+
|
7
|
+
pq = Edamame::PersistentQueue.new(
|
8
|
+
:queue => { :type => 'BeanstalkQueue', :uris => ['localhost:11210'] },
|
9
|
+
:store => { :type => 'TyrantStore', :uri => ':11212' }
|
10
|
+
)
|
11
|
+
|
12
|
+
periodic_log = Monkeyshines::Monitor::PeriodicLogger.new(:iters => 1000, :time => 30)
|
13
|
+
pq.queue.empty_all do |job|
|
14
|
+
periodic_log.periodically{ [ job.tube, job.priority, job.delay, job.scheduling, job.obj['key'] ] }
|
15
|
+
end
|
data/bin/stats.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$: << File.dirname(__FILE__)+'/../../lib'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'edamame'
|
5
|
+
require 'monkeyshines/monitor'
|
6
|
+
|
7
|
+
pq = Edamame::PersistentQueue.new(
|
8
|
+
:tube => ARGV[0],
|
9
|
+
:queue => { :type => 'BeanstalkQueue', :uris => ['localhost:11210'] },
|
10
|
+
:store => { :type => 'TyrantStore', :uri => ':11212' }
|
11
|
+
)
|
12
|
+
|
13
|
+
p pq.stats
|
data/bin/sync.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$: << File.dirname(__FILE__)+'/../../lib'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'edamame'
|
5
|
+
require 'monkeyshines/monitor'
|
6
|
+
|
7
|
+
pq = Edamame::PersistentQueue.new(
|
8
|
+
:queue => { :type => 'BeanstalkQueue', :uris => ['localhost:11210'] },
|
9
|
+
:store => { :type => 'TyrantStore', :uri => ':11212' }
|
10
|
+
)
|
11
|
+
|
12
|
+
periodic_log = Monkeyshines::Monitor::PeriodicLogger.new(:iters => 1000, :time => 30)
|
13
|
+
pq.load do |job|
|
14
|
+
periodic_log.periodically{ [ pq.store.size, job, job.tube, job.priority, job.delay, job.obj['key'] ] }
|
15
|
+
end
|
data/bin/test_run.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$: << File.dirname(__FILE__)+'/../../lib'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'json'
|
5
|
+
require 'edamame'
|
6
|
+
|
7
|
+
broker = Edamame::Broker.new(
|
8
|
+
:queue => { :type => 'BeanstalkQueue', :uris => ['localhost:11210'] },
|
9
|
+
:store => { :type => 'TyrantStore', :uri => ':11212' }
|
10
|
+
)
|
11
|
+
|
12
|
+
broker.work do |job|
|
13
|
+
Monkeyshines.logger.info [job, job.scheduling, job.stats, job.obj].inspect
|
14
|
+
end
|
data/edamame.gemspec
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{edamame}
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Philip (flip) Kromer"]
|
12
|
+
s.date = %q{2009-08-23}
|
13
|
+
s.description = %q{
|
14
|
+
|
15
|
+
Edamame combines the Beanstalk priority queue with a Tokyo Tyrant database and God monitoring to produce a persistent distributed priority job queue system.
|
16
|
+
|
17
|
+
Like beanstalk, it is fast, lightweight, distributed, priority queuing, reliable scheduling; it adds persistence, named jobs and job querying/enumeration.
|
18
|
+
|
19
|
+
}
|
20
|
+
s.email = %q{flip@infochimps.org}
|
21
|
+
s.executables = ["edamame-ps", "empty_all.rb", "stats.rb", "sync.rb", "test_run.rb"]
|
22
|
+
s.extra_rdoc_files = [
|
23
|
+
"LICENSE.textile",
|
24
|
+
"README.textile"
|
25
|
+
]
|
26
|
+
s.files = [
|
27
|
+
".document",
|
28
|
+
".gitignore",
|
29
|
+
"LICENSE.textile",
|
30
|
+
"README.textile",
|
31
|
+
"Rakefile",
|
32
|
+
"VERSION",
|
33
|
+
"app/edamame_san/config.ru",
|
34
|
+
"app/edamame_san/config.yml",
|
35
|
+
"app/edamame_san/config/.gitignore",
|
36
|
+
"app/edamame_san/edamame_san.rb",
|
37
|
+
"app/edamame_san/public/favicon.ico",
|
38
|
+
"app/edamame_san/public/images/edamame_logo.icns",
|
39
|
+
"app/edamame_san/public/images/edamame_logo.ico",
|
40
|
+
"app/edamame_san/public/images/edamame_logo.png",
|
41
|
+
"app/edamame_san/public/images/edamame_logo_2.icns",
|
42
|
+
"app/edamame_san/public/javascripts/application.js",
|
43
|
+
"app/edamame_san/public/javascripts/jquery/jquery-ui.js",
|
44
|
+
"app/edamame_san/public/javascripts/jquery/jquery.js",
|
45
|
+
"app/edamame_san/public/stylesheets/application.css",
|
46
|
+
"app/edamame_san/public/stylesheets/layout.css",
|
47
|
+
"app/edamame_san/views/layout.haml",
|
48
|
+
"app/edamame_san/views/load.haml",
|
49
|
+
"app/edamame_san/views/root.haml",
|
50
|
+
"bin/edamame-ps",
|
51
|
+
"bin/empty_all.rb",
|
52
|
+
"bin/stats.rb",
|
53
|
+
"bin/sync.rb",
|
54
|
+
"bin/test_run.rb",
|
55
|
+
"edamame.gemspec",
|
56
|
+
"lib/edamame.rb",
|
57
|
+
"lib/edamame/job.rb",
|
58
|
+
"lib/edamame/queue.rb",
|
59
|
+
"lib/edamame/queue/beanstalk.rb",
|
60
|
+
"lib/edamame/rescheduled.rb",
|
61
|
+
"lib/edamame/scheduling.rb",
|
62
|
+
"lib/edamame/store.rb",
|
63
|
+
"lib/edamame/store/base.rb",
|
64
|
+
"lib/edamame/store/tyrant_store.rb",
|
65
|
+
"lib/methods.txt",
|
66
|
+
"spec/edamame_spec.rb",
|
67
|
+
"spec/spec_helper.rb",
|
68
|
+
"utils/god/README-god.textile",
|
69
|
+
"utils/god/beanstalkd_god.rb",
|
70
|
+
"utils/god/edamame.god",
|
71
|
+
"utils/god/god-etc-init-dot-d-example",
|
72
|
+
"utils/god/god_email.rb",
|
73
|
+
"utils/god/god_process.rb",
|
74
|
+
"utils/god/god_site_config.rb",
|
75
|
+
"utils/god/sinatra_god.rb",
|
76
|
+
"utils/god/tyrant_god.rb",
|
77
|
+
"utils/simulation/Add Percent Variation.vi",
|
78
|
+
"utils/simulation/Harmonic Average.vi",
|
79
|
+
"utils/simulation/Rescheduling Simulation.aliases",
|
80
|
+
"utils/simulation/Rescheduling Simulation.lvlps",
|
81
|
+
"utils/simulation/Rescheduling Simulation.lvproj",
|
82
|
+
"utils/simulation/Rescheduling.vi",
|
83
|
+
"utils/simulation/Weighted Average.vi"
|
84
|
+
]
|
85
|
+
s.homepage = %q{http://github.com/mrflip/edamame}
|
86
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
87
|
+
s.require_paths = ["lib"]
|
88
|
+
s.rubygems_version = %q{1.3.5}
|
89
|
+
s.summary = %q{Beanstalk + Tokyo Tyrant = Edamame, a fast persistent distributed priority job queue.}
|
90
|
+
s.test_files = [
|
91
|
+
"spec/edamame_spec.rb",
|
92
|
+
"spec/spec_helper.rb"
|
93
|
+
]
|
94
|
+
|
95
|
+
if s.respond_to? :specification_version then
|
96
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
97
|
+
s.specification_version = 3
|
98
|
+
|
99
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
100
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
101
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
102
|
+
else
|
103
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
104
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
105
|
+
end
|
106
|
+
else
|
107
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
108
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
109
|
+
end
|
110
|
+
end
|
data/lib/edamame.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'wukong/extensions'
|
2
|
+
require 'monkeyshines/utils/logger'
|
3
|
+
require 'monkeyshines/utils/factory_module'
|
4
|
+
require 'beanstalk-client'
|
5
|
+
require 'edamame/scheduling'
|
6
|
+
require 'edamame/job'
|
7
|
+
require 'edamame/queue'
|
8
|
+
require 'edamame/store'
|
9
|
+
|
10
|
+
module Edamame
|
11
|
+
|
12
|
+
class PersistentQueue
|
13
|
+
DEFAULT_CONFIG = {
|
14
|
+
:queue => { :type => :beanstalk, :pool => ['localhost:11300'] }
|
15
|
+
}
|
16
|
+
attr_reader :tube, :store, :queue
|
17
|
+
def initialize options={}
|
18
|
+
@tube = options[:tube] || :default
|
19
|
+
@store = Edamame::Store.create options[:store]
|
20
|
+
@queue = Edamame::Queue.create options[:queue].merge(:default_tube => @tube)
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Add a new Job to the queue
|
25
|
+
#
|
26
|
+
def put job, *args
|
27
|
+
job.tube = self.tube if job.tube.blank?
|
28
|
+
self.tube = job.tube
|
29
|
+
return if store.include?(job.key)
|
30
|
+
store.save job
|
31
|
+
queue.put job, *args
|
32
|
+
end
|
33
|
+
|
34
|
+
def tube= _tube
|
35
|
+
return if @tube == _tube
|
36
|
+
puts "#{self.class} setting tube to #{_tube}, was #{@tube}"
|
37
|
+
queue.tube = @tube = _tube
|
38
|
+
end
|
39
|
+
|
40
|
+
# Alias for put(job)
|
41
|
+
def << job
|
42
|
+
put job
|
43
|
+
end
|
44
|
+
|
45
|
+
# Retrieve named record
|
46
|
+
def get key
|
47
|
+
Edamame::Job.from_hash store.get(key)
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Request a job fom the queue for processing
|
52
|
+
#
|
53
|
+
def reserve timeout=nil
|
54
|
+
job = queue.reserve(timeout)
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Remove the job from the queue.
|
59
|
+
#
|
60
|
+
def delete job
|
61
|
+
store.delete job.key
|
62
|
+
queue.delete job
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Returns the job to the queue, to be re-run later.
|
67
|
+
#
|
68
|
+
# release'ing a job acknowledges it was completed, successfully or not
|
69
|
+
#
|
70
|
+
def release job
|
71
|
+
job.update!
|
72
|
+
store.save job
|
73
|
+
queue.release job, job.priority, job.scheduling.delay
|
74
|
+
end
|
75
|
+
|
76
|
+
#
|
77
|
+
# Shelves the job.
|
78
|
+
#
|
79
|
+
def bury job
|
80
|
+
store.bury job
|
81
|
+
queue.bury job
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# Returns each job as it appears in the queue.
|
86
|
+
#
|
87
|
+
# all jobs -- active, inactive, running, etc -- are returned,
|
88
|
+
# and in some arbitrary order.
|
89
|
+
#
|
90
|
+
def each *args, &block
|
91
|
+
store.each do |key, job_hsh|
|
92
|
+
yield Edamame::Job.from_hash(job_hsh)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# Loads all jobs from the backing store into the queue.
|
98
|
+
#
|
99
|
+
def load &block
|
100
|
+
hoard do |job|
|
101
|
+
yield(job) if block
|
102
|
+
unless store.include?(job.key)
|
103
|
+
store.save job
|
104
|
+
end
|
105
|
+
end
|
106
|
+
unhoard &block
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns a hash of stats about the store and queue
|
110
|
+
def stats
|
111
|
+
{ :store_stats => store.stats,
|
112
|
+
:queue_stats => queue.stats,
|
113
|
+
:tube => self.tube }
|
114
|
+
end
|
115
|
+
|
116
|
+
protected
|
117
|
+
#
|
118
|
+
# Destructively strips the beanstalkd queue of all of its jobs.
|
119
|
+
#
|
120
|
+
# This is the only way (I know) to enumerate all of the jobs in the queue --
|
121
|
+
# certainly the only way that respects concurrency.
|
122
|
+
#
|
123
|
+
# You shouldn't use this in general; the point of the backing store is to
|
124
|
+
# allow exactly such queries and enumeration. See #each instead.
|
125
|
+
#
|
126
|
+
def hoard &block
|
127
|
+
queue.empty tube, &block
|
128
|
+
end
|
129
|
+
|
130
|
+
#
|
131
|
+
# Loads all jobs from the backing store into the queue.
|
132
|
+
#
|
133
|
+
# The queue must be emptied of all jobs before running this command:
|
134
|
+
# otherwise jobs will be duplicated.
|
135
|
+
#
|
136
|
+
def unhoard &block
|
137
|
+
store.each do |key, hsh|
|
138
|
+
job = Edamame::Job.from_hash hsh
|
139
|
+
self.tube = job.tube
|
140
|
+
yield(job) if block
|
141
|
+
queue.put job
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
#
|
146
|
+
#
|
147
|
+
#
|
148
|
+
def log line
|
149
|
+
Monkeyshines.logger.info line
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
class Broker < PersistentQueue
|
154
|
+
def reschedule job
|
155
|
+
delay = job.scheduling.delay
|
156
|
+
if delay
|
157
|
+
# log_job job, 'rescheduled', delay, (Time.now + delay).to_flat, job.scheduling.to_flat.join
|
158
|
+
release job
|
159
|
+
else
|
160
|
+
# log_job job, 'deleted'
|
161
|
+
delete job
|
162
|
+
end
|
163
|
+
end
|
164
|
+
def log_job job, *stuff
|
165
|
+
log [job.tube, job.priority, job.delay, job.obj['key'], *stuff].flatten.join("\t")
|
166
|
+
end
|
167
|
+
def work timeout=10, &block
|
168
|
+
loop do
|
169
|
+
job = reserve(timeout) or break
|
170
|
+
result = block.call(job)
|
171
|
+
job.update!
|
172
|
+
reschedule job
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
module Wuclan
|
179
|
+
module Domains
|
180
|
+
module Twitter
|
181
|
+
module Scrape
|
182
|
+
TwitterSearchJob = Struct.new(
|
183
|
+
:query_term,
|
184
|
+
:priority,
|
185
|
+
:prev_items,
|
186
|
+
:prev_rate,
|
187
|
+
:prev_span_min,
|
188
|
+
:prev_span_max
|
189
|
+
)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|