magent 0.4.2 → 0.5.0

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.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,7 @@
1
+ *~
2
+ config/gitspace.yml
3
+ lib/couchmapper
4
+ lib/discm
5
+ log/*
6
+ public/stylesheets/**/*.css
7
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'mongo', '~> 1.0'
4
+ gem 'uuidtools'
5
+
6
+ gem 'em-websocket'
7
+
@@ -0,0 +1,21 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ addressable (2.2.1)
5
+ bson (1.1)
6
+ em-websocket (0.1.4)
7
+ addressable (>= 2.1.1)
8
+ eventmachine (>= 0.12.9)
9
+ eventmachine (0.12.10)
10
+ mongo (1.1)
11
+ bson (>= 1.0.5)
12
+ uuidtools (2.1.1)
13
+
14
+ PLATFORMS
15
+ ruby
16
+
17
+ DEPENDENCIES
18
+ bson
19
+ em-websocket
20
+ mongo
21
+ uuidtools
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 David A. Cuadrado
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
+ NONINFRINGEMENT. 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.
@@ -18,7 +18,7 @@ see examples/
18
18
 
19
19
  == REQUIREMENTS:
20
20
 
21
- * mongodb >= 1.4
21
+ * mongodb >= 1.6
22
22
  * mongo >= 1.0.0 (gem install mongo)
23
23
 
24
24
  == INSTALL:
@@ -26,6 +26,42 @@ see examples/
26
26
  * rake gem
27
27
  * sudo gem install pkg/*.gem
28
28
 
29
+ == USAGE:
30
+
31
+ include Magent::Async in your classes:
32
+
33
+ class MyClass
34
+ include Magent::Async
35
+
36
+ def self.process_task
37
+ puts "Processing task"
38
+ end
39
+ end
40
+
41
+ enqueue with priority 1:
42
+
43
+ MyClass.async.process_task.commit!(1)
44
+
45
+ start the worker:
46
+
47
+ magent start
48
+
49
+
50
+ == RAILS SUPPORT
51
+
52
+ = initializer
53
+
54
+ Magent.setup(YAML.load_file(Rails.root.join('config', 'magent.yml')),
55
+ Rails.env, { :logger => Rails.logger }
56
+
57
+
58
+ = starting the worker
59
+
60
+ to run the jobs in rails type:
61
+
62
+ rake magent:start
63
+
64
+
29
65
  == LICENSE:
30
66
 
31
67
  (The MIT License)
data/Rakefile CHANGED
@@ -1,27 +1,55 @@
1
1
  require 'rubygems'
2
- gem 'hoe', '>= 2.1.0'
3
- require 'hoe'
4
- require 'fileutils'
5
- require './lib/magent'
2
+ require 'rake'
6
3
 
7
- Hoe.plugin :newgem
8
- # Hoe.plugin :website
9
- # Hoe.plugin :cucumberfeatures
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "magent"
8
+ gem.summary = %Q{Simple job queue system based on mongodb}
9
+ gem.description = %Q{Simple job queue system based on mongodb}
10
+ gem.email = "krawek@gmail.com"
11
+ gem.homepage = "http://github.com/dcu/magent"
12
+ gem.authors = ["David A. Cuadrado"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ gem.add_dependency "mongo"
15
+ gem.add_dependency "em-websocket"
16
+ gem.add_dependency "uuidtools"
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
22
+
23
+ require 'rake/testtask'
24
+ Rake::TestTask.new(:test) do |test|
25
+ test.libs << 'lib' << 'test'
26
+ test.pattern = 'test/**/test_*.rb'
27
+ test.verbose = true
28
+ end
10
29
 
11
- # Generate all the Rake tasks
12
- # Run 'rake -T' to see list of generated tasks (from gem root directory)
13
- $hoe = Hoe.spec 'magent' do
14
- self.developer 'David Cuadrado', 'krawek@gmail.com'
15
- self.post_install_message = ''
16
- self.rubyforge_name = self.name
17
- self.extra_deps = [['mongo','>= 0.1.0'],
18
- ['uuidtools', '>= 2.0.0']]
30
+ begin
31
+ require 'rcov/rcovtask'
32
+ Rcov::RcovTask.new do |test|
33
+ test.libs << 'test'
34
+ test.pattern = 'test/**/test_*.rb'
35
+ test.verbose = true
36
+ end
37
+ rescue LoadError
38
+ task :rcov do
39
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
40
+ end
19
41
  end
20
42
 
21
- require 'newgem/tasks'
22
- Dir['tasks/**/*.rake'].each { |t| load t }
43
+ task :test => :check_dependencies
23
44
 
24
- # TODO - want other tests/tasks run by default? Add them to the list
25
- # remove_task :default
26
- # task :default => [:spec, :features]
45
+ task :default => :test
27
46
 
47
+ require 'rake/rdoctask'
48
+ Rake::RDocTask.new do |rdoc|
49
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "magent #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.0
data/bin/magent CHANGED
@@ -1,23 +1,33 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ if File.exist?("config/environments") && File.exist?("app/models") # rails
4
+ require Dir.getwd + '/config/environment'
5
+ end
6
+
3
7
  $:.unshift File.dirname(__FILE__)+"/../lib/"
4
8
  require 'magent'
5
9
  require 'optparse'
6
10
  require 'fileutils'
7
11
 
12
+
8
13
  def usage(option_parser, error = nil)
9
14
  $stderr.puts error if error
10
15
  $stderr.puts option_parser
11
16
  exit 1
12
17
  end
13
18
 
14
- options = {}
19
+ options = {:piddir => "/tmp", :type => :async, :queue => :default}
15
20
 
16
21
  optparser = OptionParser.new do |opts|
17
- opts.banner = "Usage: #{$0} [options] <start|stop|restart>\n\nExample: magent -t carl1 -a /path/to/agent.rb -d -P /tmp restart\n\nOptions:"
22
+ opts.banner = "Usage: #{$0} [options] -Q <queue> <start|stop|restart>\n\nExample: magent -d -P /tmp -Q default restart\n\nOptions:"
18
23
 
19
24
  opts.on("-a PATH", "--agent=PATH", "Path to agent") do |o|
20
25
  options[:agent] = o
26
+ options[:type] = :actor
27
+ end
28
+
29
+ opts.on("-Q QUEUE", "--queue=QUEUE", "queue to use. default=default") do |o|
30
+ options[:queue] = o
21
31
  end
22
32
 
23
33
  opts.on("-t ID", "--identifier=ID", "Identifier") do |o|
@@ -51,32 +61,35 @@ rescue => e
51
61
  exit 0
52
62
  end
53
63
 
54
- if !options[:agent]
55
- usage(optparser, "Error: --agent is required")
64
+ if args.empty?
65
+ usage(optparser, "not enough arguments")
56
66
  end
57
67
 
58
- load options[:agent]
59
-
60
- if Magent.current_actor.nil?
61
- usage(optparser, "Use Magent.register(YourActor.new) to register an actor")
68
+ if options[:agent]
69
+ load options[:agent]
62
70
  end
63
71
 
64
72
  class Controller
65
- def initialize(actor, opts)
73
+ attr_reader :options
74
+
75
+ def initialize(opts)
66
76
  @options = opts
67
- @actor = actor
77
+
78
+ @queue = @options[:queue]
68
79
 
69
80
  @options[:log_path] ||= Dir.getwd
70
81
 
71
- @identity = @options[:identifier] || Magent::Utils.underscore(actor.class.to_s)
82
+ @identity = @options[:identifier] || Magent::Utils.underscore(@options[:queue].to_s)
72
83
  @identity << "-#{Socket.gethostname.split('.')[0]}"
84
+
85
+ $stderr.puts ">> Starting magent in #{@options[:type]} model"
73
86
  end
74
87
 
75
88
  def start
76
89
  if @options[:daemonize] && @options[:piddir]
77
90
  run_as_daemon
78
91
  else
79
- Magent::Processor.new(@actor).run!
92
+ Magent::Processor.new(self.channel).run!
80
93
  end
81
94
  end
82
95
 
@@ -104,6 +117,10 @@ class Controller
104
117
  start
105
118
  end
106
119
 
120
+ def channel
121
+ @channel ||= (@options[:type] == :async) ? Magent::AsyncChannel.new(@queue) : Magent::ActorChannel.new(@queue)
122
+ end
123
+
107
124
  private
108
125
  def run_as_daemon
109
126
  daemonize
@@ -115,7 +132,7 @@ class Controller
115
132
  end
116
133
  end
117
134
 
118
- Magent::Processor.new(@actor).run!
135
+ Magent::Processor.new(self.channel).run!
119
136
  end
120
137
 
121
138
  def pid_file
@@ -136,4 +153,4 @@ class Controller
136
153
  end
137
154
  end
138
155
 
139
- Controller.new(Magent.current_actor, options).send(args.shift)
156
+ Controller.new(options).send(args.shift)
@@ -25,6 +25,6 @@ end
25
25
  Magent.register(Worker.new)
26
26
 
27
27
  if $0 == __FILE__
28
- Magent::Processor.new(Magent.current_actor).run!
28
+ Magent::Processor.new(Worker.channel).run!
29
29
  end
30
30
 
@@ -28,6 +28,6 @@ end
28
28
  Magent.register(Error.new)
29
29
 
30
30
  if $0 == __FILE__
31
- Magent::Processor.new(Magent.current_actor).run!
31
+ Magent::Processor.new(Error.channel).run!
32
32
  end
33
33
 
@@ -0,0 +1,41 @@
1
+ $:.unshift File.dirname(__FILE__)+"/../../lib/"
2
+ require 'rubygems'
3
+ require 'magent'
4
+ require 'mongo_mapper'
5
+
6
+
7
+ MongoMapper.database = "test"
8
+ Magent.database = "test"
9
+
10
+ class Thing
11
+ include MongoMapper::Document
12
+ include Magent::Async
13
+
14
+ key :_id, String
15
+ key :name
16
+
17
+ def process_something(arg)
18
+ puts "Processing: #{arg}"
19
+ end
20
+
21
+ def process_nothing
22
+ puts "Processing..."
23
+ end
24
+
25
+ def self.foo
26
+ puts "MAX PRIORITY"
27
+ end
28
+ end
29
+
30
+
31
+ thing = Thing.create(:_id => "foo")
32
+
33
+ # 3 messages
34
+ thing.async.process_something("testing").commit!
35
+ thing.async.process_nothing.commit!
36
+ Thing.async.find(thing.id).process_something("testing2").commit!
37
+ Thing.async.foo.commit!(1)
38
+
39
+ Magent::Processor.new(Magent::AsyncChannel.new(:default)).run!
40
+
41
+
@@ -1,4 +1,5 @@
1
1
  $:.unshift File.dirname(__FILE__)+"/../../lib/"
2
+ require 'rubygems'
2
3
  require 'magent'
3
4
 
4
5
  # Use: magent /path/to/this/file
@@ -32,6 +33,6 @@ end
32
33
  Magent.register(Bot.new)
33
34
 
34
35
  if $0 == __FILE__
35
- Magent::Processor.new(Magent.current_actor).run!
36
+ Magent::Processor.new(Bot.channel).run!
36
37
  end
37
38
 
@@ -22,6 +22,6 @@ end
22
22
  Magent.register(Stats.new)
23
23
 
24
24
  if $0 == __FILE__
25
- Magent::Processor.new(Magent.current_actor).run!
25
+ Magent::Processor.new(Stats.channel).run!
26
26
  end
27
27
 
@@ -1,62 +1,114 @@
1
1
  $:.unshift(File.dirname(__FILE__)) unless
2
2
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
3
 
4
+ require 'rubygems'
4
5
  require 'mongo'
5
6
  require 'set'
6
7
  require 'uuidtools'
7
8
 
9
+ require 'magent/failure'
10
+
8
11
  require 'magent/utils'
9
12
  require 'magent/generic_channel'
10
- require 'magent/channel'
13
+ require 'magent/actor_channel'
11
14
  require 'magent/push'
12
15
  require 'magent/actor'
13
16
  require 'magent/processor'
14
17
 
18
+ require 'magent/async'
19
+ require 'magent/async_channel'
20
+
21
+ require 'magent/railtie' if defined?(Rails)
22
+
23
+ if defined?(EventMachine::WebSocket)
24
+ require 'magent/web_socket_server'
25
+ end
26
+
15
27
  module Magent
16
- VERSION = '0.4.2'
28
+ @@database_name = "magent"
17
29
 
18
- @@db_name = 'magent'
19
- @@host = 'localhost'
20
- @@port = '27017'
21
- @@username = nil
22
- @@password = nil
30
+ @@config = {
31
+ "host" => "0.0.0.0",
32
+ "port" => 27017
33
+ }
23
34
 
24
- def self.host=(host)
25
- @@host = host
26
- @@port = port
35
+ def self.connection
36
+ @@connection ||= Mongo::Connection.new
27
37
  end
28
38
 
29
- def self.port=(port)
30
- @@port = 27017
39
+ def self.logger
40
+ connection.logger
31
41
  end
32
42
 
33
- def self.auth(username,password)
34
- @@username = username
35
- @@password = password
43
+ def self.connection=(new_connection)
44
+ @@connection = new_connection
36
45
  end
37
46
 
38
- def self.db_name=(db_name)
39
- @@db_name = db_name
47
+ def self.database=(name)
48
+ @@database = nil
49
+ @@database_name = name
40
50
  end
41
51
 
42
- def self.connection
43
- return @@connection if defined?(@@connection)
44
- @@connection = Mongo::Connection.new(@@host, @@port)
45
- @@connection.add_auth(@@db_name, @@username, @@password) if @@username && @@password
52
+ def self.database
53
+ @@database ||= Magent.connection.db(@@database_name)
54
+ end
46
55
 
47
- @@connection
56
+ def self.config
57
+ @@config
48
58
  end
49
59
 
50
- def self.connection=(new_connection)
51
- @@connection = new_connection
60
+ def self.config=(config)
61
+ @@config = config
52
62
  end
53
63
 
54
- def self.database=(name)
55
- @@database = Magent.connection.db(name)
64
+ def self.connect(environment, options={})
65
+ raise 'Set config before connecting. Magent.config = {...}' if config.blank?
66
+
67
+ env = config_for_environment(environment)
68
+ Magent.connection = Mongo::Connection.new(env['host'], env['port'], options)
69
+ Magent.database = env['database']
70
+ Magent.database.authenticate(env['username'], env['password']) if env['username'] && env['password']
56
71
  end
57
72
 
58
- def self.database
59
- @@database ||= Magent.connection.db(@@db_name)
73
+ def self.setup(config, environment = nil, options = {})
74
+ self.config = config
75
+ connect(environment, options)
76
+ end
77
+
78
+ # deprecated
79
+ def self.host=(host)
80
+ @@config['host'] = host
81
+ end
82
+
83
+ def self.port=(port)
84
+ @@config['port'] = port
85
+ end
86
+
87
+ def self.db_name=(db_name)
88
+ @@database_name = db_name
89
+ end
90
+
91
+ def self.auth(username, passwd)
92
+ @@config['username'] = username
93
+ @@config['password'] = passwd
94
+ end
95
+
96
+ private
97
+ def self.config_for_environment(environment)
98
+ env = environment ? config[environment] : config
99
+
100
+ return env if env['uri'].blank?
101
+
102
+ uri = URI.parse(env['uri'])
103
+ raise InvalidScheme.new('must be mongodb') unless uri.scheme == 'mongodb'
104
+
105
+ {
106
+ 'host' => uri.host,
107
+ 'port' => uri.port,
108
+ 'database' => uri.path.gsub(/^\//, ''),
109
+ 'username' => uri.user,
110
+ 'password' => uri.password,
111
+ }
60
112
  end
61
113
  end
62
114