labor 0.1

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) Brett Buddin
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/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # Labor
2
+
3
+ A wrapper for "gearman-ruby" which provides an easy mechanism for managing your jobs. Jobs are just Ruby classes/modules which respond to the `perform` method.
4
+
5
+ ## Get Started
6
+
7
+ Basic `Rakefile`:
8
+
9
+ require 'labor'
10
+ require 'labor/tasks'
11
+
12
+ class TestJob
13
+ def self.perform
14
+ puts "Hello, world!"
15
+
16
+ true
17
+ end
18
+ end
19
+
20
+ class AnotherTest
21
+ def self.perform
22
+ puts "Hello, world... again!"
23
+
24
+ true
25
+ end
26
+ end
27
+
28
+ Labor.servers = ["10.0.0.1:4370", "10.0.0.2:4370"]
29
+
30
+ Let's run the worker:
31
+
32
+ $ export ABILITIES=test-job,another-test
33
+ $ rake labor:work
34
+
35
+ The `ABILITIES` environment variable can accept multiple job names; each seperated by a comma.
36
+
37
+ ## Configuration
38
+
39
+ Labor also allows you to load in a configuration file along with your worker. This configuration file is written in Ruby and offers a simple DSL (similar to the one present in Capistrano) for setting variables.
40
+
41
+ Configs look like this:
42
+
43
+ # settings.rb
44
+
45
+ set :foo, "bar"
46
+ set :i_am, "at the #{bar}"
47
+
48
+ group :credentials do
49
+ set :username, "murkturgler"
50
+ set :password, "supersecret"
51
+ end
52
+
53
+
54
+ The config file would then be loaded in like this:
55
+
56
+ Labor.config File.join(File.dirname(__FILE__), 'settings.rb')
57
+
58
+ When the worker is started up, Labor will load this config into the `@config` instance variable of your job class/module. You'll then be able to retrieve keys from the config within your job.
59
+
60
+ class TestJob
61
+ def self.perform
62
+ puts "Hey! I'm #{@config[:i_am]}"
63
+ #=> "Hey! I'm at the bar"
64
+
65
+ puts "Here's my username: #{@config.credentials.username}"
66
+ #=> "Here's my username: murkturgler"
67
+
68
+ true
69
+ end
70
+ end
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ begin
2
+ require "jeweler"
3
+
4
+ Jeweler::Tasks.new do |gem|
5
+ gem.name = "labor"
6
+ gem.version = "0.1"
7
+ gem.summary = "More portable jobs for Gearman workers."
8
+ gem.description = <<-desc
9
+ Wrapper for gearman-ruby that provides a different, and more portable, way of defining jobs.
10
+ desc
11
+ gem.email = "brett@intraspirit.net"
12
+ gem.homepage = "http://github.com/brettbuddin/labor"
13
+ gem.date = Time.now.strftime('%Y-%m-%d')
14
+ gem.authors = ["Brett Buddin"]
15
+ gem.files = %w( README.md Rakefile LICENSE )
16
+ gem.files += Dir["*", "{lib}/**/*"]
17
+ gem.add_dependency "gearman-ruby"
18
+ gem.add_dependency "json"
19
+
20
+ gem.has_rdoc = false
21
+ end
22
+
23
+ Jeweler::GemcutterTasks.new
24
+ rescue LoadError
25
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
26
+ end
27
+
28
+ begin
29
+ require 'rspec/core/rake_task'
30
+
31
+ RSpec::Core::RakeTask.new('spec') do |t|
32
+ t.pattern = FileList['spec/**/*_spec.rb']
33
+ end
34
+
35
+ task :test do
36
+ Rake::Task['spec'].invoke
37
+ end
38
+ end
data/labor.gemspec ADDED
@@ -0,0 +1,61 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
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{labor}
8
+ s.version = "0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Brett Buddin"]
12
+ s.date = %q{2011-02-19}
13
+ s.description = %q{ Wrapper for gearman-ruby that provides a different, and more portable, way of defining jobs.
14
+ }
15
+ s.email = %q{brett@intraspirit.net}
16
+ s.extra_rdoc_files = [
17
+ "LICENSE",
18
+ "README.md"
19
+ ]
20
+ s.files = [
21
+ "LICENSE",
22
+ "README.md",
23
+ "Rakefile",
24
+ "labor.gemspec",
25
+ "lib/labor.rb",
26
+ "lib/labor/config.rb",
27
+ "lib/labor/core_ext.rb",
28
+ "lib/labor/helpers.rb",
29
+ "lib/labor/tasks.rb",
30
+ "lib/labor/version.rb",
31
+ "lib/labor/worker.rb"
32
+ ]
33
+ s.homepage = %q{http://github.com/brettbuddin/labor}
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = %q{1.3.7}
36
+ s.summary = %q{More portable jobs for Gearman workers.}
37
+ s.test_files = [
38
+ "spec/config_spec.rb",
39
+ "spec/files/sample_config.rb",
40
+ "spec/labor_spec.rb",
41
+ "spec/spec_helper.rb",
42
+ "spec/worker_spec.rb"
43
+ ]
44
+
45
+ if s.respond_to? :specification_version then
46
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
+ s.add_runtime_dependency(%q<gearman-ruby>, [">= 0"])
51
+ s.add_runtime_dependency(%q<json>, [">= 0"])
52
+ else
53
+ s.add_dependency(%q<gearman-ruby>, [">= 0"])
54
+ s.add_dependency(%q<json>, [">= 0"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<gearman-ruby>, [">= 0"])
58
+ s.add_dependency(%q<json>, [">= 0"])
59
+ end
60
+ end
61
+
data/lib/labor.rb ADDED
@@ -0,0 +1,58 @@
1
+ require 'gearman'
2
+ require 'json'
3
+
4
+ require 'labor/version'
5
+ require 'labor/core_ext'
6
+ require 'labor/helpers'
7
+ require 'labor/worker'
8
+ require 'labor/config'
9
+
10
+ module Labor
11
+ # Sets the server addresses that we'd like to connect to.
12
+ #
13
+ # servers - The String address of the server or an Array
14
+ # of server addresses.
15
+ #
16
+ # Examples
17
+ #
18
+ # Labor.servers '10.3.4.19:4730'
19
+ # Labor.servers ['10.3.4.19:4730', '10.3.4.20:4730']
20
+ #
21
+ # Returns the Array of server addresses or String if only one was given.
22
+ def self.servers=(servers)
23
+ @servers = servers
24
+ end
25
+
26
+ # Returns the list of server addresses we'd like to connect to.
27
+ #
28
+ # Returns the Array of server addresses. Defaults to localhost:4730
29
+ # if nothing has been set.
30
+ def self.servers
31
+ @servers || ["localhost:#{Gearman::Util::DEFAULT_PORT}"]
32
+ end
33
+
34
+ # Loads in a config file.
35
+ #
36
+ # file_name - The String path to the file.
37
+ #
38
+ # Examples
39
+ #
40
+ # Labor.config 'settings.rb'
41
+ #
42
+ # Returns the Labor::Config instance.
43
+ def self.config=(file_name)
44
+ @config = Labor::Config.new.load file_name
45
+ end
46
+
47
+ # Returns the configuration object for our application.
48
+ #
49
+ # Returns the Labor::Config instance. Defaults to a new config
50
+ # if nothing has been set.
51
+ def self.config
52
+ @config ||= Labor::Config.new
53
+ end
54
+
55
+ class << self
56
+ attr_accessor :verbose
57
+ end
58
+ end
@@ -0,0 +1,103 @@
1
+ # Configuration manager for the worker. Treat it like a Hash.
2
+ # A hash that has a tiny DSL for setting values to it and
3
+ # supports grouping.
4
+ #
5
+ # For example:
6
+ #
7
+ # config = Config.new
8
+ # config[:foo] = "bar"
9
+ # config.set :hello, "world"
10
+ # config.group :a_group do
11
+ # set :three_two_one, "let's jam!"
12
+ # end
13
+ #
14
+ # config.foo #=> "bar"
15
+ # config.hello #=> "world"
16
+ # config.a_group.three_two_one #=> "let's jam"
17
+ #
18
+ module Labor
19
+ class Config
20
+ include Enumerable
21
+
22
+ def initialize
23
+ @config = {}
24
+ end
25
+
26
+ # Loads a config file.
27
+ #
28
+ # file_name - The String path to the file.
29
+ #
30
+ # Returns Config instance.
31
+ def load(file_name)
32
+ instance_eval(File.read(file_name))
33
+ self
34
+ end
35
+
36
+ # Assigns a value to a key.
37
+ #
38
+ # key - The Symbol key name.
39
+ # value - Anything you'd like to assign to the key.
40
+ #
41
+ # Returns the value of the key.
42
+ def set(key, value)
43
+ @config[key.to_sym] = value
44
+ end
45
+ alias_method :[]=, :set
46
+
47
+ # Retreives the value of a key.
48
+ #
49
+ # key - The Symbol key name.
50
+ #
51
+ # Returns the value of the key.
52
+ def get(key)
53
+ @config[key.to_sym]
54
+ end
55
+ alias_method :[], :get
56
+
57
+ # Deletes a key from the config.
58
+ #
59
+ # key - The Symbol key name.
60
+ #
61
+ # Returns the value of the key.
62
+ def delete(key)
63
+ @config.delete key.to_sym
64
+ end
65
+
66
+ # Checks if a key is set in the config.
67
+ #
68
+ # key - The Symbol key name.
69
+ #
70
+ # Returns a Boolean of whether or not the key exists.
71
+ def exists?(key)
72
+ @config.has_key? key.to_sym
73
+ end
74
+
75
+ # Call a block for each key in the config.
76
+ #
77
+ # block - The Block to execute for each element.
78
+ #
79
+ # Returns a Boolean of whether or not the key exists.
80
+ def each(&block)
81
+ @config.each(&block)
82
+ end
83
+
84
+
85
+ # Checks if a key is set in the config.
86
+ #
87
+ # key - The Symbol key name
88
+ #
89
+ # Returns a Boolean of whether or not the key exists.
90
+ def group(key, &block)
91
+ @config[key.to_sym] ||= Config.new
92
+ @config[key.to_sym].instance_eval(&block) if block_given?
93
+ end
94
+
95
+ private
96
+
97
+ def method_missing(sym, *args)
98
+ if args.length == 0 && @config.has_key?(sym)
99
+ get(sym)
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,3 @@
1
+ Dir["#{File.dirname(__FILE__)}/core_ext/*.rb"].each do |path|
2
+ require "labor/core_ext/#{File.basename(path, '.rb')}"
3
+ end
@@ -0,0 +1,30 @@
1
+ module Labor
2
+ module Helpers
3
+ def classify(word)
4
+ word.split('-').each { |part| part[0] = part[0].chr.upcase }.join
5
+ end
6
+
7
+ def constantize(camel_cased_word)
8
+ camel_cased_word = camel_cased_word.to_s
9
+
10
+ if camel_cased_word.include?('-')
11
+ camel_cased_word = classify(camel_cased_word)
12
+ end
13
+
14
+ names = camel_cased_word.split('::')
15
+ names.shift if names.empty? || names.first.empty?
16
+
17
+ constant = Object
18
+ names.each do |name|
19
+ constant = constant.const_get(name) || constant.const_missing(name)
20
+ end
21
+ constant
22
+ end
23
+
24
+ def log(str)
25
+ if Labor.verbose
26
+ puts "#{Time.now.strftime('%I:%M:%S %d-%m-%Y')}: #{str}"
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ # Rake tasks for Labor
2
+ #
3
+ # require 'labor/tasks'
4
+
5
+ namespace :labor do
6
+ task :work do
7
+ require 'labor'
8
+
9
+ abilities = ENV['ABILITIES'].to_s.split(',')
10
+
11
+ unless abilities.empty?
12
+ worker = Labor::Worker.new *abilities
13
+ else
14
+ abort "Please set ABILITIES environment variable (e.g. ABILITIES=say-hai,say-hello)"
15
+ end
16
+
17
+ if ENV['PIDFILE']
18
+ File.open(ENV['PIDFILE'], 'w') { |f| f << Process.pid.to_s }
19
+ end
20
+ Labor.verbose = ENV['VERBOSE']
21
+
22
+ worker.work
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module Labor
2
+ VERSION = Version = 0.1
3
+ end
@@ -0,0 +1,78 @@
1
+ module Labor
2
+ class Worker
3
+ include Helpers
4
+
5
+ def initialize(*abilities)
6
+ @worker = Gearman::Worker.new(Labor.servers)
7
+ add_abilities(abilities)
8
+ end
9
+
10
+ # Starts the work loop.
11
+ #
12
+ # Returns nothing.
13
+ def work
14
+ register_signals
15
+ loop { @worker.work or break }
16
+ end
17
+
18
+ private
19
+
20
+ # Registers abilities with the worker and announces them to the server.
21
+ #
22
+ # abilities - The Array of ability strings.
23
+ #
24
+ # Returns nothing.
25
+ def add_abilities(abilities)
26
+ abilities.each do |ability|
27
+ klass = constantize(classify(ability))
28
+ klass.instance_variable_set(:@config, Labor.config)
29
+
30
+ @worker.add_ability(ability) do |data, job|
31
+ begin
32
+ payload = JSON.parse data
33
+ klass.perform(payload, job)
34
+ rescue Exception => e
35
+ log "Job failed: #{e.inspect}"
36
+ return false
37
+ end
38
+ end
39
+
40
+ if klass.respond_to?(:after_perform)
41
+ @worker.after_ability(ability) do |result, data|
42
+ begin
43
+ payload = JSON.parse data
44
+ klass.after_perform(payload, result)
45
+ rescue Exception => e
46
+ log "After job failed: #{e.inspect}"
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ # Sets the procline of the program. You can observe it via `top`.
54
+ #
55
+ # str - The String to be assigned to the procline.
56
+ #
57
+ # Returns the String assigned to the procline.
58
+ def procline=(str)
59
+ $0 = "labor: #{str}"
60
+ end
61
+
62
+ # Registers trapping signals with the worker.
63
+ #
64
+ # Returns nothing.
65
+ def register_signals
66
+ %w(INT TERM).each do |signal|
67
+ trap signal do
68
+ @worker.worker_enabled = false
69
+ if @worker.status == :waiting
70
+ trap signal, "DEFAULT"
71
+ exit
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,80 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Labor::Config do
4
+ before(:each) do
5
+ @config = Labor::Config.new
6
+ end
7
+
8
+ it "loads config from a file" do
9
+ @config.load File.join(File.dirname(__FILE__), 'files', 'sample_config.rb')
10
+ @config.get(:foo).should == "bar"
11
+ end
12
+
13
+ it "allows write access to a key" do
14
+ @config.set(:foo, "bar")
15
+ @config.get(:foo).should == "bar"
16
+ end
17
+
18
+ it "allows read access to a key" do
19
+ @config.set(:foo, "bar")
20
+ @config.get(:foo).should == "bar"
21
+ end
22
+
23
+ it "allows read access to keys via bracket method" do
24
+ @config.set(:foo, "bar")
25
+ @config[:foo].should == "bar"
26
+ end
27
+
28
+ it "provides access to keys using methods" do
29
+ @config.set(:foo, "bar")
30
+ @config.foo.should == "bar"
31
+ end
32
+
33
+ it "allows write access to keys via bracket method" do
34
+ @config[:foo] = "bar"
35
+ @config.get(:foo).should == "bar"
36
+ end
37
+
38
+ it "allows deletion of a key" do
39
+ @config.set(:foo, "a noob")
40
+ @config.delete(:foo)
41
+ @config.get(:foo).should be_nil
42
+ end
43
+
44
+ it "allows checking existence of a key" do
45
+ @config.set(:foo, "bar")
46
+ @config.exists?(:foo)
47
+ end
48
+
49
+ it "have each defined" do
50
+ @config.respond_to?(:each)
51
+ end
52
+
53
+ it "allow configs to use keys as in-line variables" do
54
+ @config.instance_eval <<-CONFIG
55
+ set :foo, "bar"
56
+ set :i_am, "at the \#{foo}"
57
+ CONFIG
58
+ @config.get(:i_am).should == "at the bar"
59
+ end
60
+
61
+ describe :grouping do
62
+ before(:each) do
63
+ @config.instance_eval <<-CONFIG
64
+ group :test do
65
+ set :foo, "bar"
66
+ set :i_am, "at the \#{foo}"
67
+ end
68
+ CONFIG
69
+ end
70
+
71
+ it "can retreive a key from a group" do
72
+ @config.get(:test).get(:foo).should == "bar"
73
+ end
74
+
75
+ it "can assign a key to a group" do
76
+ @config.test[:omg] = "wtf"
77
+ @config.get(:test).get(:omg).should == "wtf"
78
+ end
79
+ end
80
+ end
@@ -0,0 +1 @@
1
+ set :foo, "bar"
@@ -0,0 +1,15 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Labor do
4
+ describe :servers do
5
+ it "assigns a single server" do
6
+ Labor.servers = "10.0.0.1:4370"
7
+ Labor.servers.should == "10.0.0.1:4370"
8
+ end
9
+
10
+ it "assigns a list of servers" do
11
+ Labor.servers = ["10.0.0.1:4370", "10.0.0.2:4370"]
12
+ Labor.servers.should == ["10.0.0.1:4370", "10.0.0.2:4370"]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift File.expand_path("../lib", File.dirname(__FILE__))
2
+
3
+ require 'rspec'
4
+ require 'labor'
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ class Test
4
+ def self.perform
5
+ puts "Hello"
6
+ end
7
+ end
8
+
9
+ describe Labor::Worker do
10
+ before(:each) do
11
+ @worker = Labor::Worker.new 'test'
12
+ end
13
+
14
+ it "assigns abilities" do
15
+ real_worker = @worker.instance_variable_get(:@worker)
16
+ real_worker.instance_variable_get(:@abilities).should have_key("test")
17
+ end
18
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: labor
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - Brett Buddin
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2011-02-19 00:00:00 -05:00
17
+ default_executable:
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: gearman-ruby
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: json
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
42
+ version: "0"
43
+ type: :runtime
44
+ version_requirements: *id002
45
+ description: " Wrapper for gearman-ruby that provides a different, and more portable, way of defining jobs.\n"
46
+ email: brett@intraspirit.net
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files:
52
+ - LICENSE
53
+ - README.md
54
+ files:
55
+ - LICENSE
56
+ - README.md
57
+ - Rakefile
58
+ - labor.gemspec
59
+ - lib/labor.rb
60
+ - lib/labor/config.rb
61
+ - lib/labor/core_ext.rb
62
+ - lib/labor/helpers.rb
63
+ - lib/labor/tasks.rb
64
+ - lib/labor/version.rb
65
+ - lib/labor/worker.rb
66
+ - spec/config_spec.rb
67
+ - spec/files/sample_config.rb
68
+ - spec/labor_spec.rb
69
+ - spec/spec_helper.rb
70
+ - spec/worker_spec.rb
71
+ has_rdoc: true
72
+ homepage: http://github.com/brettbuddin/labor
73
+ licenses: []
74
+
75
+ post_install_message:
76
+ rdoc_options: []
77
+
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ segments:
94
+ - 0
95
+ version: "0"
96
+ requirements: []
97
+
98
+ rubyforge_project:
99
+ rubygems_version: 1.3.7
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: More portable jobs for Gearman workers.
103
+ test_files:
104
+ - spec/config_spec.rb
105
+ - spec/files/sample_config.rb
106
+ - spec/labor_spec.rb
107
+ - spec/spec_helper.rb
108
+ - spec/worker_spec.rb