cloudq 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Tom Wilson
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.
data/bin/cloudq ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), '..','lib', 'cloudq')
4
+
5
+ require 'fileutils'
6
+
7
+ if ARGV.first
8
+ project = ARGV.first
9
+ FileUtils.mkdir_p project
10
+
11
+ config_ru = ["require 'cloudq'", "run Cloudq::App"].join("\n")
12
+ File.open(File.join(project, 'config.ru'),'w').write(config_ru)
13
+ gemfile = ['source :rubygems', "gem 'thin'", "gem 'cloudq'"].join("\n")
14
+ File.open(File.join(project, 'Gemfile'),'w').write(gemfile)
15
+ puts "****** Sucessfully Created #{project} *******"
16
+ else
17
+ puts "Cloudq Remote Job Queue Framework..."
18
+ puts "(Please supply a project name for your cloudq server...)"
19
+ end
20
+ # puts "Running Cloudq on port:9292"
21
+ # puts "Press Ctrl-C to exit"
22
+ # # try to run in current directory
23
+ # gem 'rack', '>=0'
24
+ # load Gem.bin_path('rack', 'rackup', version)
data/lib/cloudq/app.rb ADDED
@@ -0,0 +1,46 @@
1
+ module Cloudq
2
+ class App < Sinatra::Base
3
+ register Sinatra::Async
4
+
5
+ use Rack::Params
6
+
7
+ def self.version
8
+ "0.0.6"
9
+ end
10
+
11
+ aget '/' do
12
+ body "Welcome to Cloudq Framework"
13
+ end
14
+
15
+ # Post Job to the Queue
16
+ apost "/:queue" do |q|
17
+ halt 500 if params["job"].nil?
18
+ Job.create(params["job"].merge(:queue => q))
19
+ status = { :status => "success" }.to_json
20
+ body status
21
+ end
22
+
23
+
24
+ # Get Job from the Queue
25
+ aget "/:queue" do |q|
26
+ job = Job.where(:queue => q.to_sym, :workflow_state => :queued).first
27
+ if job
28
+ job.reserve!
29
+ body job.to_json
30
+ else
31
+ status = { :status => :empty }.to_json
32
+ body status
33
+ end
34
+ end
35
+
36
+ # Remove Job from the Queue
37
+ adelete "/:queue/:id" do |q, id|
38
+ job = Job.where(:queue => q.to_sym, :id => id).first
39
+ halt 404 unless job
40
+ job.delete!
41
+ status = { :status => "success" }.to_json
42
+ body status
43
+ end
44
+
45
+ end
46
+ end
data/lib/cloudq/job.rb ADDED
@@ -0,0 +1,47 @@
1
+ if ENV['MONGOHQ_URL']
2
+ MongoMapper.config = {:production => {'uri' => ENV['MONGOHQ_URL']}}
3
+ MongoMapper.connect(:production)
4
+ else
5
+ MongoMapper.database = 'cloudq'
6
+ end
7
+
8
+ module Cloudq
9
+ class Job
10
+ include MongoMapper::Document
11
+ before_validation :write_initial_state, :on => :create
12
+
13
+ key :queue, String
14
+ key :klass, String
15
+ key :args, Hash
16
+ key :workflow_state, String
17
+
18
+ timestamps!
19
+
20
+ include Workflow
21
+
22
+ workflow do
23
+ state :queued do
24
+ event :reserve, :transitions_to => :reserved
25
+ end
26
+ state :reserved do
27
+ event :delete, :transitions_to => :deleted
28
+ end
29
+ state :deleted
30
+ end
31
+
32
+ def load_workflow_state
33
+ self[:workflow_state]
34
+ end
35
+
36
+ def persist_workflow_state(new_value)
37
+ self[:workflow_state] = new_value
38
+ save!
39
+ end
40
+
41
+ private
42
+ def write_initial_state
43
+ update_attributes(self.class.workflow_column => current_state.to_s) if load_workflow_state.blank?
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ module Cloudq
2
+ VERSION = '0.0.7'
3
+ end
data/lib/cloudq.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'bundler/setup'
2
+ require 'json'
3
+ require 'mongo_mapper'
4
+ require 'sinatra'
5
+ require 'sinatra/async'
6
+ require 'workflow'
7
+
8
+ require_relative 'rack/params'
9
+
10
+ module Cloudq; end
11
+
12
+ require_relative 'cloudq/job'
13
+ require_relative 'cloudq/app'
14
+
15
+
@@ -0,0 +1,49 @@
1
+ module Rack
2
+ class Params
3
+ URL_ENCODED = %r{^application/x-www-form-urlencoded}
4
+ JSON_ENCODED = %r{^application/json}
5
+
6
+ # A middle ware to parse params. This will parse both the
7
+ # query string parameters and the body and place them into
8
+ # the _params_ hash of the Goliath::Env for the request.
9
+ #
10
+ # @example
11
+ # use Rack::Params
12
+ #
13
+ # -- Borrowed from Goliath -- goliath.io
14
+
15
+ def initialize(app)
16
+ @app = app
17
+ end
18
+
19
+ def call(env)
20
+ env['params'] = retrieve_params(env)
21
+ @app.call(env)
22
+ end
23
+
24
+ def retrieve_params(env)
25
+ params = {}
26
+ params.merge!(::Rack::Utils.parse_nested_query(env['QUERY_STRING']))
27
+
28
+ if env['rack.input']
29
+ post_params = ::Rack::Utils::Multipart.parse_multipart(env)
30
+ unless post_params
31
+ body = env['rack.input'].read
32
+ env['rack.input'].rewind
33
+
34
+ post_params = case(env['CONTENT_TYPE'])
35
+ when URL_ENCODED then
36
+ ::Rack::Utils.parse_nested_query(body)
37
+ when JSON_ENCODED then
38
+ JSON.parse(body)
39
+ else
40
+ {}
41
+ end
42
+ end
43
+ params.merge!(post_params)
44
+ end
45
+
46
+ params
47
+ end
48
+ end
49
+ end
data/readme.md ADDED
@@ -0,0 +1,171 @@
1
+ # Cloudq Framework
2
+
3
+ Cloudq is a rack-based job queue framework.
4
+
5
+ ## What does that mean?
6
+
7
+ Cloudq is a job queue, but instead of containing a ton of features, it focuses on doing job queue basics:
8
+
9
+ * Publish a Job to a Queue
10
+ * Reserve a Job from a Queue
11
+ * Delete a Job from a Queue
12
+
13
+ Using the rack application architecture, and taking advantage of rack middleware, adding features or embedding
14
+ into other applications is very easy.
15
+
16
+ Currently, it does depend on access to a mongodb datastore. Either the standard localhost or you can
17
+ set the MONGOHQ_URL env variable. This does not mean that any application you join with Cloudq needs to write to mongodb, just the job queue is connected to mongo.
18
+
19
+ # What about security?
20
+ # What about monitoring?
21
+ # etc???
22
+
23
+ The answer is simple, RACK MIDDLEWARE! If you want to implement ssl encryption and enforce SSL traffic, use
24
+ rack middleware. If you want to attach a slick admin
25
+ interface that monitors your queues, then use the rack
26
+ map function to attach another rack-based application to your config.ru file.
27
+
28
+ It really is that easy, and Cloudq gives you the flexibility to integrate almast anyway you can think of.
29
+
30
+ # How do I get started?
31
+
32
+ 1. Install Mongodb
33
+
34
+ First you need to install MongoDb and have a mongodb service running. Or you can signup for a free account on
35
+ MongoHq.com.
36
+
37
+ 2. Install Ruby version 1.9.2 or above
38
+
39
+ Make sure you have Ruby 1.9.2 installed on your machine, if you do not have 1.9.2, check out [RVM](https://rvm.beginrescueend.com/). Ruby 1.9.2 comes with rubygems, which will allow you to install the cloudq gem.
40
+
41
+ 3. Install the Cloudq Gem
42
+
43
+ gem install cloudq
44
+
45
+ 4. Build your cloudq server
46
+
47
+ cloudq [your name]
48
+
49
+ This will create a directory and add a config.ru and Gemfile. And if you don't want to add any other features,
50
+ you are good to go. All you have to do is cd into your directory and run:
51
+
52
+
53
+ thin start
54
+
55
+ And your cloudq server is up and running!
56
+
57
+ ----------------
58
+
59
+ # Deploy
60
+
61
+ You can deploy Cloudq just like any rails application, but Heroku is an awesome platform to deploy:
62
+
63
+ # make sure you have your project in a git repo
64
+
65
+ git init
66
+ git add .
67
+ git commit -am "First Commit"
68
+
69
+ # deploy to heroku in 2 simple steps
70
+
71
+ heroku create
72
+ git push heroku master
73
+
74
+
75
+ # Contribution
76
+
77
+ Feel free to for fork the code and make pull requests.. But also create some Rack Middleware that helps add an
78
+ awesome feature stack to the Cloudq.
79
+
80
+ Here is a link to an awesome chapter in the Rails 3 in a Nutshell on Rack.
81
+
82
+ [http://rails-nutshell.labs.oreilly.com/ch07.html](http://rails-nutshell.labs.oreilly.com/ch07.html)
83
+
84
+
85
+ # API
86
+
87
+ The api pattern is like so:
88
+
89
+ / [ Queue Name ] / [ Action ]
90
+
91
+ and
92
+
93
+ / [ Queue Name ] / [ Action ] / [ id ]
94
+
95
+
96
+ ## Add to Queue
97
+
98
+ post /myqueue
99
+ klass: 'Archive'
100
+ args: { [ args here ] }
101
+
102
+ ## Reserve Message
103
+
104
+ get /myqueue
105
+
106
+ # JSON =>
107
+ {
108
+ klass: 'Archive'
109
+ args: {}
110
+ id: 1234
111
+ }
112
+
113
+ ## Delete Message
114
+
115
+ delete /myqueue/1234
116
+
117
+
118
+ ---
119
+
120
+ You can create as many queues as you want, when you post your first
121
+ message in the queue, it will create that queue, and when you perform
122
+ reserver, the worker will pull in a first in, first out process.
123
+
124
+ ---
125
+
126
+ ## Publish Job in Ruby
127
+
128
+ gem install cloudq_client
129
+
130
+ require 'cloudq_client/publish'
131
+
132
+ Cloudq::Connection.url = 'http://donuts.com'
133
+ Cloudq::Publish.job(:make_donuts, 'Donut', :types => [:glazed,
134
+ :chocolate])
135
+
136
+
137
+ ---
138
+
139
+ ### Worker in Ruby
140
+
141
+ gem install cloudq_client
142
+
143
+ require 'cloudq_client/cosume'
144
+ require 'Donut'
145
+
146
+ Cloudq::Connection.url = 'http://donuts.com'
147
+ loop do
148
+ Cloudq::Consume.job(:make_donuts)
149
+ sleep 5
150
+ end
151
+
152
+
153
+ ---
154
+
155
+ The worker can be implemented in any language, but the api is designed
156
+ to return a json message that will call the perform class method and
157
+ pass in arguments to that method for processing:
158
+
159
+ klass = Object.const_get(payload[:klass].capitalize)
160
+ klass.perform(*payload[:args])
161
+
162
+
163
+
164
+ ---
165
+
166
+
167
+
168
+
169
+
170
+
171
+
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloudq
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.7
6
+ platform: ruby
7
+ authors:
8
+ - Tom Wilson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-19 00:00:00 -04:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rspec
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 2.5.0
25
+ type: :development
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack-test
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: "0"
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: bundler
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: thin
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ type: :runtime
59
+ version_requirements: *id004
60
+ - !ruby/object:Gem::Dependency
61
+ name: sinatra
62
+ prerelease: false
63
+ requirement: &id005 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ type: :runtime
70
+ version_requirements: *id005
71
+ - !ruby/object:Gem::Dependency
72
+ name: bson_ext
73
+ prerelease: false
74
+ requirement: &id006 !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: "0"
80
+ type: :runtime
81
+ version_requirements: *id006
82
+ - !ruby/object:Gem::Dependency
83
+ name: mongo_mapper
84
+ prerelease: false
85
+ requirement: &id007 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: "0"
91
+ type: :runtime
92
+ version_requirements: *id007
93
+ - !ruby/object:Gem::Dependency
94
+ name: eventmachine
95
+ prerelease: false
96
+ requirement: &id008 !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: 1.0.0.beta.3
102
+ type: :runtime
103
+ version_requirements: *id008
104
+ - !ruby/object:Gem::Dependency
105
+ name: async_sinatra
106
+ prerelease: false
107
+ requirement: &id009 !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: "0"
113
+ type: :runtime
114
+ version_requirements: *id009
115
+ - !ruby/object:Gem::Dependency
116
+ name: workflow
117
+ prerelease: false
118
+ requirement: &id010 !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: "0"
124
+ type: :runtime
125
+ version_requirements: *id010
126
+ description: The Cloudq Framework makes it easy to build remote job queue servers
127
+ email:
128
+ - tom@jackhq.com
129
+ executables:
130
+ - cloudq
131
+ extensions: []
132
+
133
+ extra_rdoc_files: []
134
+
135
+ files:
136
+ - lib/cloudq/app.rb
137
+ - lib/cloudq/job.rb
138
+ - lib/cloudq/version.rb
139
+ - lib/cloudq.rb
140
+ - lib/rack/params.rb
141
+ - LICENSE
142
+ - readme.md
143
+ - bin/cloudq
144
+ has_rdoc: true
145
+ homepage: http://github.com/twilson63/cloudq
146
+ licenses: []
147
+
148
+ post_install_message:
149
+ rdoc_options: []
150
+
151
+ require_paths:
152
+ - - lib
153
+ required_ruby_version: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: "0"
159
+ required_rubygems_version: !ruby/object:Gem::Requirement
160
+ none: false
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: 1.3.6
165
+ requirements: []
166
+
167
+ rubyforge_project:
168
+ rubygems_version: 1.6.2
169
+ signing_key:
170
+ specification_version: 3
171
+ summary: A Ruby Framework for a Remote Job Queue Server
172
+ test_files: []
173
+