resque-mongo-groups 0.5

Sign up to get free protection for your applications and to get access to all the features.
data/.bundle/config ADDED
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_DISABLE_SHARED_GEMS: "1"
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/HISTORY.md ADDED
File without changes
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Gheorghita Catalin Bordianu
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
File without changes
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ require 'bundler/setup'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ $LOAD_PATH.unshift 'lib'
5
+
6
+ Dir['tasks/*.rake'].each do |f|
7
+ load File.expand_path(f)
8
+ end
9
+
10
+ task :default => :test
11
+
12
+ desc "Run tests"
13
+ task :test do
14
+ Dir['test/*_test.rb'].each do |f|
15
+ require File.expand_path(f)
16
+ end
17
+ end
@@ -0,0 +1,129 @@
1
+ require 'rubygems'
2
+ gem 'resque-mongo'
3
+ require 'resque'
4
+ require 'resque/server'
5
+
6
+ module Resque
7
+ module Plugins
8
+ end
9
+ end
10
+
11
+ require 'resque_groups/tracked_job'
12
+ require 'resque_groups/server'
13
+
14
+ module Resque::Plugins::Groups
15
+
16
+ def job_groups
17
+ self.mongo ||= ENV['MONGO'] || 'localhost:27017'
18
+ @job_groups ||= @db.collection('job_groups')
19
+ end
20
+
21
+ # Triggered whenever a job belonging to group 'gid' has been enqueued. If there's no entry for that group in the 'job_groups'
22
+ # collection, create one and record a timestamp. Otherwise, just increment a total count of enqueued jobs for that group
23
+ def upsert_group(gid)
24
+ if job_groups.find_one({'_id' => gid}).nil?
25
+ job_groups.update( {'_id' => gid},
26
+ {
27
+ '$inc' => {'total' => 1},
28
+ '$set' => {'started_at' => Time.now}
29
+ }, {:upsert => true})
30
+ else
31
+ job_groups.update( {'_id' => gid},
32
+ {
33
+ '$inc' => {'total' => 1}
34
+ }, {:upsert => true})
35
+ end
36
+ #Resque.print_groups
37
+ job_groups.count
38
+ end
39
+
40
+ # Increments the 'completed' count of the group with id 'gid'.
41
+ # Also merge the increment operation with optional custom
42
+ # atomic operations.
43
+ def record_performed_job(gid, atomic_op = nil)
44
+ op = {'$inc' => {'completed' => 1}}
45
+ if atomic_op
46
+ op['$inc'].merge!(atomic_op.delete('$inc')) if atomic_op['$inc']
47
+ op.merge!(atomic_op)
48
+ end
49
+ job_groups.update( {'_id' => gid}, op , {:upsert => true})
50
+ #Resque.print_groups
51
+ end
52
+
53
+ # Increments the 'failed' count of the group with id 'gid'
54
+ def record_failed_job(gid, exception)
55
+ job_groups.update( {'_id' => gid},
56
+ {
57
+ '$inc' => {'failed' => 1},
58
+ '$push' => {'exceptions' => exception.inspect}
59
+ }, {:upsert => true})
60
+ #Resque.print_groups
61
+ end
62
+
63
+ def record_delayed_job(gid)
64
+ job_groups.update( {'_id' => gid},
65
+ {
66
+ '$inc' => {'delayed' => 1}
67
+ }, {:upsert => true})
68
+ #Resque.print_groups
69
+ end
70
+
71
+ def delete_delayed_job(gid)
72
+ job_groups.update( {'_id' => gid},
73
+ {
74
+ '$inc' => {'delayed' => -1}
75
+ }, {:upsert => true})
76
+ #Resque.print_groups
77
+ end
78
+
79
+ # Clears all the groups that are being stored in the job_groups collection
80
+ def reset_groups_queue
81
+ job_groups.remove
82
+ end
83
+
84
+ # Deletes a group from the job_groups collection
85
+ def remove_group(gid)
86
+ job_groups.remove({'_id' => gid})
87
+ end
88
+
89
+ # Returns the stats for a given job group
90
+ def group_stats(gid)
91
+ job_groups.find_one({'_id' => gid})
92
+ end
93
+
94
+ def groups_stats(start, count)
95
+ job_groups.find({}, :skip => start, :limit => count, :sort => ['_id', 1]).to_a
96
+ end
97
+
98
+ def groups_count
99
+ job_groups.count
100
+ end
101
+
102
+ # Given a set of args, looks through all the args that are Hashes for a :group_id key (the inject line replaces string keys with their symbols)
103
+ def parse_gid(*args)
104
+ gid = nil
105
+ args.flatten.each do |arg|
106
+ next unless arg.kind_of? Hash
107
+ sym_arg = arg.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
108
+ if !sym_arg[:group_id].nil?
109
+ gid = sym_arg[:group_id]
110
+ break
111
+ end
112
+ end
113
+ gid
114
+ end
115
+
116
+ def print_groups
117
+ puts "--------------------"
118
+ job_groups.find().each do |row|
119
+ puts row.inspect
120
+ end
121
+ puts "--------------------"
122
+ end
123
+
124
+ end
125
+
126
+ Resque.extend Resque::Plugins::Groups
127
+ Resque::Server.class_eval do
128
+ include ResqueGroups::Server
129
+ end
@@ -0,0 +1,23 @@
1
+
2
+
3
+ # Extend Resque::Server to add tabs
4
+ module ResqueGroups
5
+
6
+ module Server
7
+
8
+ def self.included(base)
9
+
10
+ base.class_eval do
11
+
12
+ get "/groups" do
13
+ erb File.read(File.join(File.dirname(__FILE__), 'server/views/groups.erb'))
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ Resque::Server.tabs << 'Groups'
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,43 @@
1
+ <%start = params[:start].to_i %>
2
+ <%count = params[:count] ? params[:count].to_i : 100 %>
3
+
4
+ <% groups = [resque.groups_stats(start, start + count)].flatten %>
5
+ <% size = resque.groups_count %>
6
+ <h1>Groups</h1>
7
+
8
+ <p class='intro'>
9
+ This list below contains the groups being processed.
10
+ </p>
11
+
12
+ <p class='sub'>
13
+ Showing <%= start %> to <%= start + groups.size %> of <b><%= size %></b> groups
14
+ </p>
15
+
16
+
17
+ <table>
18
+ <tr>
19
+ <th>Group</th>
20
+ <th>Started at</th>
21
+ <th>Total</th>
22
+ <th>Delayed</th>
23
+ <th>Completed</th>
24
+ <th>Failed</th>
25
+ <th>Exceptions</th>
26
+ <th>Custom field</th>
27
+ </tr>
28
+ <% groups.each do |group| %>
29
+ <tr>
30
+ <td><%= group['_id'] %></td>
31
+ <td><%= group['started_at'] %></td>
32
+ <td><%= group['total'] %></td>
33
+ <td><%= group['delayed'] %></td>
34
+ <td><%= group['completed'] %></td>
35
+ <td><%= group['failed'] %></td>
36
+ <td><%= escape_html(group['exceptions'].inspect) if group['exceptions'] %></td>
37
+ <td><%= escape_html(group['custom'].inspect) if group['custom'] %></td>
38
+ </tr>
39
+ <% end %>
40
+ </table>
41
+
42
+
43
+ <%= partial :next_more, :start => start, :count => count, :size => size %>
@@ -0,0 +1,7 @@
1
+ # require 'resque/tasks'
2
+ # will give you the resque tasks
3
+
4
+ namespace :resque do
5
+ task :setup
6
+
7
+ end
@@ -0,0 +1,58 @@
1
+ module Resque::Plugins::Groups
2
+ module TrackedJob
3
+
4
+ # The MongoDB atomic operation stored in this variable will be executed
5
+ # on the group when and if the job is complete.
6
+ # See http://www.mongodb.org/display/DOCS/Updating for a list of all atomic operations.
7
+ # e.g.:
8
+ # {'$inc' => {'custom.size' => 3}}
9
+ # {'$set' => {'custom.api_problem' => true}}
10
+ # It's highly recommended to use the "custom" field to store your data, even
11
+ # if no check is done by the plugin.
12
+ def atomic_op_on_complete
13
+ @atomic_op_on_complete
14
+ end
15
+ def atomic_op_on_complete=(op)
16
+ @atomic_op_on_complete = op
17
+ end
18
+
19
+ # resque hook, triggered immediately after a job with *args has been enqueued
20
+ def after_enqueue_count_job(*args)
21
+ gid = Resque.parse_gid(*args)
22
+ raise "The 'group_id' parameter is missing!" if gid.nil?
23
+
24
+ # If this was a scheduled/delayed job, decrement the 'delayed' counter
25
+ Resque.delete_delayed_job(gid) if !is_delayed(args).nil?
26
+
27
+ # Update the total count for the group in which the enqueued job belongs
28
+ Resque.upsert_group(gid)
29
+ end
30
+
31
+ # resque hook, triggered immediately after a job has been performed
32
+ def after_perform_update_completed(*args)
33
+ gid = Resque.parse_gid(*args)
34
+ Resque.record_performed_job(gid, atomic_op_on_complete)
35
+ end
36
+
37
+ # resque hook, triggered if a job raises any exception. uncaught exceptions propagate up to Resque::Failure
38
+ def on_failure_update_failed(exception, *args)
39
+ gid = Resque.parse_gid(*args)
40
+ Resque.record_failed_job(gid, exception)
41
+ end
42
+
43
+ # Determines if this was a delayed job or not, based on the :delayed => true arg
44
+ def is_delayed(*args)
45
+ delayed = nil
46
+ args.flatten.each do |arg|
47
+ next unless arg.kind_of? Hash
48
+ sym_arg = arg.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
49
+ if !sym_arg[:delayed].nil?
50
+ delayed = sym_arg[:delayed]
51
+ break
52
+ end
53
+ end
54
+ delayed
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,7 @@
1
+ require 'resque'
2
+
3
+ module Resque::Plugins
4
+ module Groups
5
+ Version = '0.5'
6
+ end
7
+ end
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "resque_groups/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "resque-mongo-groups"
7
+ s.version = Resque::Plugins::Groups::Version
8
+ s.platform = Gem::Platform::RUBY
9
+ s.author = 'Gheorghita Catalin Bordianu'
10
+ s.email = ['catalin@silentale.com']
11
+ s.homepage = "http://github.com/omikronn/resque-mongo-groups"
12
+ s.summary = "Keeps track of groups of jobs and their completion status"
13
+ s.description = %q{Provides a way of keeping track of batches of jobs, completion status, start time etc. using a MongoDb collection}
14
+
15
+ s.required_rubygems_version = ">= 1.3.6"
16
+ s.add_development_dependency "bundler", ">= 1.0.0"
17
+
18
+ s.rubyforge_project = "resque-mongo-groups"
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
23
+ s.require_path = 'lib'
24
+
25
+ s.add_runtime_dependency(%q<resque-mongo>, [">= 1.11.0"])
26
+
27
+ end
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
2
+ require 'resque_groups/tasks'
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resque-mongo-groups
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: "0.5"
6
+ platform: ruby
7
+ authors:
8
+ - Gheorghita Catalin Bordianu
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-03-24 00:00:00 +01:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: bundler
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 1.0.0
25
+ type: :development
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: resque-mongo
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: 1.11.0
36
+ type: :runtime
37
+ version_requirements: *id002
38
+ description: Provides a way of keeping track of batches of jobs, completion status, start time etc. using a MongoDb collection
39
+ email:
40
+ - catalin@silentale.com
41
+ executables: []
42
+
43
+ extensions: []
44
+
45
+ extra_rdoc_files: []
46
+
47
+ files:
48
+ - .bundle/config
49
+ - .gitignore
50
+ - Gemfile
51
+ - HISTORY.md
52
+ - LICENSE
53
+ - README.markdown
54
+ - Rakefile
55
+ - lib/resque_groups.rb
56
+ - lib/resque_groups/server.rb
57
+ - lib/resque_groups/server/views/groups.erb
58
+ - lib/resque_groups/tasks.rb
59
+ - lib/resque_groups/tracked_job.rb
60
+ - lib/resque_groups/version.rb
61
+ - resque-mongo-groups.gemspec
62
+ - tasks/resque_counter.rake
63
+ has_rdoc: true
64
+ homepage: http://github.com/omikronn/resque-mongo-groups
65
+ licenses: []
66
+
67
+ post_install_message:
68
+ rdoc_options: []
69
+
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 1.3.6
84
+ requirements: []
85
+
86
+ rubyforge_project: resque-mongo-groups
87
+ rubygems_version: 1.6.1
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: Keeps track of groups of jobs and their completion status
91
+ test_files: []
92
+