cloudq 0.0.7

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.
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
+