simple_worker 0.3.15 → 0.3.16

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/README.markdown CHANGED
@@ -1,8 +1,10 @@
1
- Using Simple Worker
2
-
3
1
  Getting Started
4
2
  ===============
5
3
 
4
+ [Sign up for a SimpleWorker account][1], it's free to try!
5
+
6
+ [1]: http://www.simpleworker.com/
7
+
6
8
  Configure SimpleWorker
7
9
  ----------------------
8
10
 
@@ -68,9 +70,43 @@ action in your application. This is almost the same as queuing your worker.
68
70
  worker.body = "This is the body"
69
71
  **worker.schedule(:start_at=>1.hours.since)**
70
72
 
73
+ Check Status
74
+ ------------
75
+
76
+ If you still have access to the worker object, just call:
77
+
78
+ worker.status
79
+
80
+ If you only have the job ID, call:
81
+
82
+ SimpleWorker.status(job_id)
83
+
84
+ This will return a hash like:
85
+
86
+ {"task_id"=>"ece460ce-12d8-11e0-8e15-12313b0440c6",
87
+ "status"=>"running",
88
+ "msg"=>nil,
89
+ "start_time"=>"2010-12-28T23:19:36+00:00",
90
+ "end_time"=>nil,
91
+ "duration"=>nil,
92
+ "progress"=>{"percent"=>25}}
93
+
94
+ TODO: How to access log.
95
+
96
+ Logging
97
+ -------
98
+
99
+ log "Starting to do something..."
100
+
101
+
102
+ Setting Progress
103
+ ----------------
104
+
105
+ set_progress(:percent => progress, :message => "Server running. Trying to connect...")
106
+
71
107
 
72
108
 
73
- Schedule your Worker Recurring
109
+ Schedule a Recurring Job - CRON
74
110
  ------------------------------
75
111
 
76
112
  The alternative is when you want to user it like Cron. In this case you'll probably
@@ -80,6 +116,7 @@ app starts or anything so best to keep it external.
80
116
  Create a file called 'schedule_email_worker.rb' and add this:
81
117
 
82
118
  require 'simple_worker'
119
+ require_relative 'email_worker'
83
120
 
84
121
  worker = EmailWorker.new
85
122
  worker.to = current_user.email
@@ -92,16 +129,59 @@ Now run it and your worker will be scheduled to run every hour.
92
129
  SimpleWorker on Rails
93
130
  ---------------------
94
131
 
95
- SimpleWorker only supports Rails 3+.
132
+ Rails 2.X:
96
133
 
97
- Setup:
134
+ config.gem 'simple_worker'
98
135
 
99
- - Make a workers directory at RAILS_ROOT/app/workers.
100
- - In application.rb, uncomment config.autoload_paths and put:
136
+ Rails 3.X:
101
137
 
102
- config.autoload_paths += %W(#{config.paths.app}/workers)
138
+ gem 'simple_worker'
139
+
140
+ Now you can use your workers like they're part of your app! We recommend putting your worker classes in
141
+ /app/workers path.
142
+
143
+ Configuring a Database Connection
144
+ ---------------------------------
145
+
146
+ Although you could easily do this in your worker, this makes it a bit more convenient and more importantly
147
+ it will create the connection for you. If you are using ActiveRecord, you would add the following to your
148
+ SimpleWorker config:
149
+
150
+ config.database = {
151
+ :adapter => "mysql2",
152
+ :host => "localhost",
153
+ :database => "appdb",
154
+ :username => "appuser",
155
+ :password => "secret"
156
+ }
157
+
158
+ Then before you job is run, SimpleWorker will establish the ActiveRecord connection.
159
+
160
+ Including/Merging other Ruby Classes
161
+ ------------------------------------
162
+
163
+ If you are using the Rails setup above, you can probably skip this as your models will automatically be merged.
164
+
165
+ class AvgWorker < SimpleWorker::Base
166
+
167
+ attr_accessor :aws_access_key,
168
+ :aws_secret_key,
169
+ :s3_suffix
170
+
171
+ merge File.join(File.dirname(__FILE__), "..", "app", "models", "user.rb")
172
+ merge File.join(File.dirname(__FILE__), "..", "app", "models", "account")
173
+
174
+ Or simpler yet, try using relative paths:
175
+
176
+ merge "../app/models/user"
177
+ merge "../app/models/account.rb"
178
+
179
+
180
+ Bringing in other Workers
181
+ ---------------------
103
182
 
104
- Now you can use your workers like their part of your app!
183
+ merge_worker
184
+ TODO
105
185
 
106
186
 
107
187
  Configuration Options
@@ -118,7 +198,7 @@ Eg:
118
198
  config.global_attributes[:db_user] = "sa"
119
199
  config.global_attributes[:db_pass] = "pass"
120
200
 
121
- Then in your worker, you must have:
201
+ Then in your worker, you would have the attributes defined:
122
202
 
123
203
  attr_accessor :db_user, :db_pass
124
204
 
@@ -0,0 +1,7 @@
1
+ puts "Initializing list of Rails models..."
2
+ SimpleWorker.configure do |config|
3
+ path = File.join(Rails.root, 'app/models/*.rb')
4
+ puts 'path=' + path
5
+ config.models = Dir.glob(path)
6
+ puts 'config.models=' + config.models.inspect
7
+ end
data/lib/railtie.rb ADDED
@@ -0,0 +1,23 @@
1
+ # see http://api.rubyonrails.org/classes/Rails/Railtie.html
2
+
3
+ require 'simple_worker'
4
+ require 'rails'
5
+
6
+ module SimpleWorker
7
+ class Railtie < Rails::Railtie
8
+ railtie_name :simple_worker
9
+
10
+ initializer "simple_worker.configure_rails_initialization" do |app|
11
+ puts 'railtie'
12
+ puts "Initializing list of Rails models..."
13
+ SimpleWorker.configure do |c2|
14
+ # path = File.join(File.dirname(caller[0]), '..', 'app/models/*.rb')
15
+ path = File.join(Rails.root, 'app/models/*.rb')
16
+ puts 'path=' + path
17
+ c2.models = Dir.glob(path)
18
+ puts 'config.models=' + c2.models.inspect
19
+ end
20
+
21
+ end
22
+ end
23
+ end
data/lib/simple_worker.rb CHANGED
@@ -1,180 +1,32 @@
1
1
  require 'appoxy_api'
2
2
  require 'active_support/core_ext'
3
- require File.join(File.dirname(__FILE__), 'simple_worker', 'base')
4
- require File.join(File.dirname(__FILE__), 'simple_worker', 'config')
5
- require File.join(File.dirname(__FILE__), 'simple_worker', 'used_in_worker')
3
+ require_relative 'simple_worker/service'
4
+ require_relative 'simple_worker/base'
5
+ require_relative 'simple_worker/config'
6
+ require_relative 'simple_worker/used_in_worker'
6
7
 
7
8
 
8
9
  module SimpleWorker
9
10
 
10
- class << self
11
- attr_accessor :config,
12
- :service
11
+ class << self
12
+ attr_accessor :config,
13
+ :service
13
14
 
14
- def configure()
15
- SimpleWorker.config ||= Config.new
16
- yield(config)
17
- SimpleWorker.service = Service.new(config.access_key, config.secret_key, :config=>config)
18
- end
15
+ def configure()
16
+ SimpleWorker.config ||= Config.new
17
+ yield(config)
18
+ SimpleWorker.service = Service.new(config.access_key, config.secret_key, :config=>config)
19
19
  end
20
-
21
- class Service < Appoxy::Api::Client
22
-
23
- attr_accessor :config
24
-
25
- def initialize(access_key, secret_key, options={})
26
- puts 'Starting SimpleWorker::Service...'
27
- self.config = options[:config] if options[:config]
28
- super("http://api.simpleworker.com/api/", access_key, secret_key, options)
29
- self.host = self.config.host if self.config && self.config.host
30
- end
31
-
32
- # Options:
33
- # - :callback_url
34
- # - :merge => array of files to merge in with this file
35
- def upload(filename, class_name, options={})
36
-
37
- # check whether it should upload again
38
- tmp = Dir.tmpdir()
39
- # puts 'tmp=' + tmp.to_s
40
- md5file = "simple_workr_#{class_name.gsub("::", ".")}.md5"
41
- existing_md5 = nil
42
- f = File.join(tmp, md5file)
43
- if File.exists?(f)
44
- existing_md5 = IO.read(f)
45
- # puts 'existing_md5=' + existing_md5
46
- end
47
-
48
- filename = build_merged_file(filename, options[:merge]) if options[:merge]
49
-
50
- # sys.classes[subclass].__file__
51
- # puts '__FILE__=' + Base.subclass.__file__.to_s
52
- md5 = Digest::MD5.hexdigest(File.read(filename))
53
- # puts "new md5=" + md5
54
-
55
- if md5 != existing_md5
56
- puts "#{class_name}: new code, so uploading"
57
- File.open(f, 'w') { |f| f.write(md5) }
58
- else
59
- puts "#{class_name}: same code, not uploading"
60
- end
61
-
62
- mystring = nil
63
- file = File.open(filename, "r") do |f|
64
- mystring = f.read
65
- end
66
- options = {"code"=>mystring, "class_name"=>class_name}
67
- ret = post("code/put", options)
68
- ret
69
- end
70
-
71
- def build_merged_file(filename, merge)
72
- merge = merge.dup
73
- merge << filename
74
- fname2 = File.join(Dir.tmpdir(), File.basename(filename))
75
- # puts 'fname2=' + fname2
76
- # puts 'merged_file_array=' + merge.inspect
77
- File.open(fname2, "w") do |f|
78
- merge.each do |m|
79
- f.write File.open(m, 'r') { |mo| mo.read }
80
- f.write "\n\n"
81
- end
82
- end
83
- fname2
84
- end
85
-
86
- def add_sw_params(hash_to_send)
87
- # todo: remove secret key?? Can use worker service from within a worker without it now
88
- hash_to_send["sw_access_key"] = self.access_key
89
- hash_to_send["sw_secret_key"] = self.secret_key
90
- end
91
-
92
- # class_name: The class name of a previously upload class, eg: MySuperWorker
93
- # data: Arbitrary hash of your own data that your task will need to run.
94
- def queue(class_name, data={})
95
- if !data.is_a?(Array)
96
- data = [data]
97
- end
98
- hash_to_send = {}
99
- hash_to_send["payload"] = data
100
- hash_to_send["class_name"] = class_name
101
- add_sw_params(hash_to_send)
102
- if defined?(RAILS_ENV)
103
- hash_to_send["rails_env"] = RAILS_ENV
104
- end
105
- return queue_raw(class_name, hash_to_send)
106
-
107
- end
108
-
109
- def queue_raw(class_name, data={})
110
- params = nil
111
- hash_to_send = data
112
- hash_to_send["class_name"] = class_name
113
- ret = post("queue/add", hash_to_send)
114
- ret
115
-
116
- end
117
-
118
-
119
- #
120
- # schedule: hash of scheduling options that can include:
121
- # Required:
122
- # - start_at: Time of first run - DateTime or Time object.
123
- # Optional:
124
- # - run_every: Time in seconds between runs. If ommitted, task will only run once.
125
- # - delay_type: Fixed Rate or Fixed Delay. Default is fixed_delay.
126
- # - end_at: Scheduled task will stop running after this date (optional, if ommitted, runs forever or until cancelled)
127
- # - run_times: Task will run exactly :run_times. For instance if :run_times is 5, then the task will run 5 times.
128
- #
129
- def schedule(class_name, data, schedule)
130
- raise "Schedule must be a hash." if !schedule.is_a? Hash
131
- # if !data.is_a?(Array)
132
- # data = [data]
133
- # end
134
- hash_to_send = {}
135
- hash_to_send["payload"] = data
136
- hash_to_send["class_name"] = class_name
137
- hash_to_send["schedule"] = schedule
138
- add_sw_params(hash_to_send)
139
- # puts 'about to send ' + hash_to_send.inspect
140
- ret = post("scheduler/schedule", hash_to_send)
141
- ret
142
- end
143
-
144
- def cancel_schedule(scheduled_task_id)
145
- raise "Must include a schedule id." if scheduled_task_id.blank?
146
- hash_to_send = {}
147
- hash_to_send["scheduled_task_id"] = scheduled_task_id
148
- ret = post("scheduler/cancel", hash_to_send)
149
- ret
150
- end
151
-
152
- def get_schedules()
153
- hash_to_send = {}
154
- ret = get("scheduler/list", hash_to_send)
155
- ret
156
- end
157
-
158
- def status(task_id)
159
- data = {"task_id"=>task_id}
160
- ret = get("task/status", data)
161
- ret
162
- end
163
-
164
- def schedule_status(schedule_id)
165
- data = {"schedule_id"=>schedule_id}
166
- ret = get("scheduler/status", data)
167
- ret
168
- end
169
-
170
- def log(task_id)
171
- data = {"task_id"=>task_id}
172
- ret = get("task/log", data)
173
- # puts 'ret=' + ret.inspect
174
- # ret["log"] = Base64.decode64(ret["log"])
175
- ret
176
- end
177
-
178
-
179
- end
180
- end
20
+ end
21
+
22
+ end
23
+
24
+ if defined?(Rails)
25
+ puts 'Rails=' + Rails.inspect
26
+ puts 'vers=' + Rails::VERSION::MAJOR.inspect
27
+ if Rails::VERSION::MAJOR == 2
28
+ require_relative 'rails2_init.rb'
29
+ else
30
+ require_relative 'railtie'
31
+ end
32
+ end
@@ -4,208 +4,239 @@ require 'digest/md5'
4
4
 
5
5
  module SimpleWorker
6
6
 
7
- class Base
7
+ class Base
8
8
 
9
- attr_accessor :task_set_id, :task_id, :schedule_id
9
+ attr_accessor :task_set_id, :task_id, :schedule_id
10
10
 
11
- class << self
12
- attr_accessor :subclass, :caller_file
13
- @merged = []
14
- @merged_workers = []
11
+ class << self
12
+ attr_accessor :subclass, :caller_file
13
+ @merged = []
14
+ @merged_workers = []
15
15
 
16
- def reset!
17
- @merged = []
18
- @merged_workers = []
19
- end
16
+ def reset!
17
+ @merged = []
18
+ @merged_workers = []
19
+ end
20
20
 
21
- def inherited(subclass)
22
- subclass.reset!
21
+ def inherited(subclass)
22
+ subclass.reset!
23
23
 
24
24
  # puts "subclass.inspect=" + subclass.inspect
25
25
  # puts 'existing caller=' + (subclass.instance_variable_defined?(:@caller_file) ? subclass.instance_variable_get(:@caller_file).inspect : "nil")
26
26
  # puts "caller=" + caller.inspect
27
27
  # splits = caller[0].split(":")
28
28
  # caller_file = splits[0] + ":" + splits[1]
29
- caller_file = caller[0][0...(caller[0].index(":in"))]
30
- caller_file = caller_file[0...(caller_file.rindex(":"))]
29
+ caller_file = caller[0][0...(caller[0].index(":in"))]
30
+ caller_file = caller_file[0...(caller_file.rindex(":"))]
31
31
  # puts 'caller_file=' + caller_file
32
- # don't need these class_variables anymore probably
33
- subclass.instance_variable_set(:@caller_file, caller_file)
34
-
35
- super
36
- end
37
-
38
- # merges the specified files.
39
- def merge(*files)
40
- files.each do |f|
41
- unless File.exist? f
42
- raise "File not found: " + f
43
- end
44
- require f
45
- @merged << File.expand_path(f)
46
- end
32
+ # don't need these class_variables anymore probably
33
+ subclass.instance_variable_set(:@caller_file, caller_file)
34
+
35
+ super
36
+ end
37
+
38
+ # merges the specified files.
39
+ # todo: don't allow multiple files per merge, just one like require
40
+ def merge(*files)
41
+ files.each do |f|
42
+ f = f.to_str
43
+ unless ends_with?(f, ".rb")
44
+ f << ".rb"
45
+ end
46
+ exists = false
47
+ if File.exist? f
48
+ exists = true
49
+ else
50
+ # try relative
51
+ f2 = File.join(File.dirname(caller[0]), f)
52
+ if File.exist? f2
53
+ exists = true
54
+ f = f2
47
55
  end
48
-
49
- def merge_worker(file, class_name)
50
- puts 'merge_worker in ' + self.name
51
- merge(file)
52
- @merged_workers << [File.expand_path(file), class_name]
53
- end
54
- end
56
+ end
57
+ unless exists
58
+ raise "File not found: " + f
59
+ end
60
+ require f
61
+ @merged << File.expand_path(f)
62
+ end
63
+ end
64
+
65
+ def ends_with?(s, suffix)
66
+ suffix = suffix.to_s
67
+ s[-suffix.length, suffix.length] == suffix
68
+ end
69
+
70
+ def merge_worker(file, class_name)
71
+ puts 'merge_worker in ' + self.name
72
+ merge(file)
73
+ @merged_workers << [File.expand_path(file), class_name]
74
+ end
75
+ end
55
76
 
56
77
 
57
- def log(str)
58
- puts str.to_s
59
- end
78
+ def log(str)
79
+ puts str.to_s
80
+ end
60
81
 
61
- def user_dir
62
- "."
63
- end
82
+ def user_dir
83
+ "."
84
+ end
64
85
 
65
- def set_progress(hash)
66
- puts 'set_progress: ' + hash.inspect
67
- end
86
+ def set_progress(hash)
87
+ puts 'set_progress: ' + hash.inspect
88
+ end
68
89
 
69
- def who_am_i?
70
- return self.class.name
71
- end
90
+ def who_am_i?
91
+ return self.class.name
92
+ end
72
93
 
73
- def uploaded?
74
- self.class.instance_variable_defined?(:@uploaded) && self.class.instance_variable_get(:@uploaded)
75
- end
94
+ def uploaded?
95
+ self.class.instance_variable_defined?(:@uploaded) && self.class.instance_variable_get(:@uploaded)
96
+ end
76
97
 
77
- # Call this if you want to run locally and get some extra features from this gem like global attributes.
78
- def run_local
98
+ # Call this if you want to run locally and get some extra features from this gem like global attributes.
99
+ def run_local
79
100
  # puts 'run_local'
80
- set_global_attributes
81
- run
82
- end
101
+ set_auto_attributes
102
+ run
103
+ end
104
+
105
+ def set_auto_attributes
106
+ set_global_attributes
107
+ end
83
108
 
84
- def set_global_attributes
85
- ga = SimpleWorker.config.global_attributes
86
- if ga && ga.size > 0
87
- ga.each_pair do |k,v|
109
+ def set_global_attributes
110
+ ga = SimpleWorker.config.global_attributes
111
+ if ga && ga.size > 0
112
+ ga.each_pair do |k, v|
88
113
  # puts "k=#{k} v=#{v}"
89
- if self.respond_to?(k)
90
- self.send("#{k}=", v)
91
- end
92
- end
93
- end
114
+ if self.respond_to?(k)
115
+ self.send("#{k}=", v)
116
+ end
94
117
  end
118
+ end
119
+ end
95
120
 
96
- # Will send in all instance_variables.
97
- def queue
121
+ # Will send in all instance_variables.
122
+ def queue
98
123
  # puts 'in queue'
99
- set_global_attributes
100
- upload_if_needed
124
+ set_auto_attributes
125
+ upload_if_needed
101
126
 
102
- response = SimpleWorker.service.queue(self.class.name, sw_get_data)
127
+ response = SimpleWorker.service.queue(self.class.name, sw_get_data)
103
128
  # puts 'queue response=' + response.inspect
104
- @task_set_id = response["task_set_id"]
105
- @task_id = response["tasks"][0]["task_id"]
106
- response
107
- end
129
+ @task_set_id = response["task_set_id"]
130
+ @task_id = response["tasks"][0]["task_id"]
131
+ response
132
+ end
108
133
 
109
- def status
110
- SimpleWorker.service.status(task_id)
111
- end
134
+ def status
135
+ SimpleWorker.service.status(task_id)
136
+ end
112
137
 
113
- def upload
114
- upload_if_needed
115
- end
138
+ def upload
139
+ upload_if_needed
140
+ end
116
141
 
117
- #
118
- # schedule: hash of scheduling options that can include:
119
- # Required:
120
- # - start_at: Time of first run - DateTime or Time object.
121
- # Optional:
122
- # - run_every: Time in seconds between runs. If ommitted, task will only run once.
123
- # - delay_type: Fixed Rate or Fixed Delay. Default is fixed_delay.
124
- # - end_at: Scheduled task will stop running after this date (optional, if ommitted, runs forever or until cancelled)
125
- # - run_times: Task will run exactly :run_times. For instance if :run_times is 5, then the task will run 5 times.
126
- #
127
- def schedule(schedule)
128
- set_global_attributes
129
- upload_if_needed
130
-
131
- response = SimpleWorker.service.schedule(self.class.name, sw_get_data, schedule)
142
+ #
143
+ # schedule: hash of scheduling options that can include:
144
+ # Required:
145
+ # - start_at: Time of first run - DateTime or Time object.
146
+ # Optional:
147
+ # - run_every: Time in seconds between runs. If ommitted, task will only run once.
148
+ # - delay_type: Fixed Rate or Fixed Delay. Default is fixed_delay.
149
+ # - end_at: Scheduled task will stop running after this date (optional, if ommitted, runs forever or until cancelled)
150
+ # - run_times: Task will run exactly :run_times. For instance if :run_times is 5, then the task will run 5 times.
151
+ #
152
+ def schedule(schedule)
153
+ set_global_attributes
154
+ upload_if_needed
155
+
156
+ response = SimpleWorker.service.schedule(self.class.name, sw_get_data, schedule)
132
157
  # puts 'schedule response=' + response.inspect
133
- @schedule_id = response["schedule_id"]
134
- response
135
- end
158
+ @schedule_id = response["schedule_id"]
159
+ response
160
+ end
136
161
 
137
- def schedule_status
138
- SimpleWorker.service.schedule_status(schedule_id)
139
- end
162
+ def schedule_status
163
+ SimpleWorker.service.schedule_status(schedule_id)
164
+ end
140
165
 
141
- # Callbacks for developer
142
- def before_upload
166
+ # Callbacks for developer
167
+ def before_upload
143
168
 
144
- end
169
+ end
145
170
 
146
- def after_upload
171
+ def after_upload
147
172
 
148
- end
173
+ end
149
174
 
150
- def before_run
175
+ def before_run
151
176
 
152
- end
177
+ end
153
178
 
154
- def after_run
179
+ def after_run
155
180
 
156
- end
181
+ end
157
182
 
158
- private
159
-
160
- def upload_if_needed
161
-
162
- before_upload
163
-
164
- puts 'upload_if_needed'
165
- # Todo, watch for this file changing or something so we can reupload
166
- unless uploaded?
167
- subclass = self.class
168
- rfile = subclass.instance_variable_get(:@caller_file) # Base.caller_file # File.expand_path(Base.subclass)
169
- puts 'rfile=' + rfile.inspect
170
- puts 'self.class.name=' + subclass.name
171
- merged = self.class.instance_variable_get(:@merged)
172
- puts 'merged1=' + merged.inspect
173
- superclass = subclass
174
- # Also get merged from subclasses up to SimpleWorker::Base
175
- while (superclass = superclass.superclass)
176
- puts 'superclass=' + superclass.name
177
- break if superclass.name == SimpleWorker::Base.name
178
- super_merged = superclass.instance_variable_get(:@merged)
183
+ private
184
+
185
+ def upload_if_needed
186
+
187
+ before_upload
188
+
189
+ puts 'upload_if_needed ' + self.class.name
190
+ # Todo, watch for this file changing or something so we can reupload
191
+ unless uploaded?
192
+ merged = self.class.instance_variable_get(:@merged)
193
+ puts 'merged1=' + merged.inspect
194
+
195
+ subclass = self.class
196
+ rfile = subclass.instance_variable_get(:@caller_file) # Base.caller_file # File.expand_path(Base.subclass)
197
+ puts 'subclass file=' + rfile.inspect
198
+ puts 'subclass.name=' + subclass.name
199
+ superclass = subclass
200
+ # Also get merged from subclasses up to SimpleWorker::Base
201
+ while (superclass = superclass.superclass)
202
+ puts 'superclass=' + superclass.name
203
+ break if superclass.name == SimpleWorker::Base.name
204
+ super_merged = superclass.instance_variable_get(:@merged)
179
205
  # puts 'merging caller file: ' + superclass.instance_variable_get(:@caller_file).inspect
180
- super_merged << superclass.instance_variable_get(:@caller_file)
181
- merged = super_merged + merged
182
- puts 'merged with superclass=' + merged.inspect
183
-
184
- end
185
- SimpleWorker.service.upload(rfile, subclass.name, :merge=>merged)
186
- self.class.instance_variable_set(:@uploaded, true)
187
- else
188
- puts 'already uploaded for ' + self.class.name
189
- end
190
- puts 'uploading merged workers'
191
- self.class.instance_variable_get(:@merged_workers).each do |mw|
192
- # to support merges in the secondary worker, we should instantiate it here, then call "upload"
193
- puts 'instantiating and uploading ' + mw[1]
194
- Kernel.const_get(mw[1]).new.upload
206
+ super_merged << superclass.instance_variable_get(:@caller_file)
207
+ merged = super_merged + merged
208
+ puts 'merged with superclass=' + merged.inspect
209
+ end
210
+ merged += SimpleWorker.config.models if SimpleWorker.config.models
211
+ SimpleWorker.service.upload(rfile, subclass.name, :merge=>merged)
212
+ self.class.instance_variable_set(:@uploaded, true)
213
+ else
214
+ puts 'already uploaded for ' + self.class.name
215
+ end
216
+ merged_workers = self.class.instance_variable_get(:@merged_workers)
217
+ puts 'now uploading merged WORKERS ' + merged_workers.inspect
218
+ merged_workers.each do |mw|
219
+ # to support merges in the secondary worker, we should instantiate it here, then call "upload"
220
+ puts 'instantiating and uploading ' + mw[1]
221
+ Kernel.const_get(mw[1]).new.upload
195
222
  # SimpleWorker.service.upload(mw[0], mw[1])
196
- end
223
+ end
197
224
 
198
- after_upload
199
- end
200
-
201
- def sw_get_data
202
- data = {}
203
- self.instance_variables.each do |iv|
204
- data[iv] = instance_variable_get(iv)
205
- end
206
- return data
207
- end
225
+ after_upload
226
+ end
208
227
 
228
+ def sw_get_data
229
+ data = {}
230
+ self.instance_variables.each do |iv|
231
+ data[iv] = instance_variable_get(iv)
232
+ end
209
233
 
234
+ config_data = {}
235
+ config_data['database'] = SimpleWorker.config.database if SimpleWorker.config.database
236
+ data[:sw_config] = config_data
237
+ return data
210
238
  end
239
+
240
+
241
+ end
211
242
  end
@@ -1,21 +1,27 @@
1
1
  module SimpleWorker
2
2
 
3
3
 
4
- # Config is used to setup the SimpleWorker client.
5
- # You must set the access_key and secret_key.
6
- #
7
- # config.global_attributes allows you to specify attributes that will automatically be set on every worker,
8
- # this is good for database connection information or things that will be used across the board.
9
- class Config
10
- attr_accessor :access_key,
11
- :secret_key,
12
- :host,
13
- :global_attributes
4
+ # Config is used to setup the SimpleWorker client.
5
+ # You must set the access_key and secret_key.
6
+ #
7
+ # config.global_attributes allows you to specify attributes that will automatically be set on every worker,
8
+ # this is good for database connection information or things that will be used across the board.
9
+ #
10
+ # config.database configures a database connection. If specified like ActiveRecord, SimpleWorker will automatically establish a connection
11
+ # for you before running your worker.
12
+ class Config
13
+ attr_accessor :access_key,
14
+ :secret_key,
15
+ :host,
16
+ :global_attributes,
17
+ :models,
18
+ :database
14
19
 
15
- def initialize
16
- @global_attributes = {}
17
- end
20
+ def initialize
21
+ @global_attributes = {}
18
22
  end
19
23
 
24
+ end
25
+
20
26
  end
21
27
 
@@ -0,0 +1,170 @@
1
+ module SimpleWorker
2
+
3
+ class Service < Appoxy::Api::Client
4
+
5
+ attr_accessor :config
6
+
7
+ def initialize(access_key, secret_key, options={})
8
+ puts 'Starting SimpleWorker::Service...'
9
+ self.config = options[:config] if options[:config]
10
+ super("http://api.simpleworker.com/api/", access_key, secret_key, options)
11
+ self.host = self.config.host if self.config && self.config.host
12
+ end
13
+
14
+ # Options:
15
+ # - :callback_url
16
+ # - :merge => array of files to merge in with this file
17
+ def upload(filename, class_name, options={})
18
+ puts "Uploading #{class_name}"
19
+ # check whether it should upload again
20
+ tmp = Dir.tmpdir()
21
+ md5file = "simple_worker_#{class_name.gsub("::", ".")}.md5"
22
+ existing_md5 = nil
23
+ f = File.join(tmp, md5file)
24
+ if File.exists?(f)
25
+ existing_md5 = IO.read(f)
26
+ end
27
+
28
+ filename = build_merged_file(filename, options[:merge]) if options[:merge]
29
+
30
+ # sys.classes[subclass].__file__
31
+ # puts '__FILE__=' + Base.subclass.__file__.to_s
32
+ md5 = Digest::MD5.hexdigest(File.read(filename))
33
+ # puts "new md5=" + md5
34
+
35
+ new_code = false
36
+ if md5 != existing_md5
37
+ puts "#{class_name}: new code, uploading"
38
+ File.open(f, 'w') { |f| f.write(md5) }
39
+ new_code = true
40
+ else
41
+ puts "#{class_name}: same code, not uploading"
42
+ end
43
+
44
+ if new_code
45
+ mystring = nil
46
+ file = File.open(filename, "r") do |f|
47
+ mystring = f.read
48
+ end
49
+ options = {"code"=>mystring, "class_name"=>class_name}
50
+ ret = post("code/put", options)
51
+ ret
52
+ end
53
+ end
54
+
55
+ def build_merged_file(filename, merge)
56
+ merge = merge.dup
57
+ merge << filename
58
+ merge.uniq!
59
+ fname2 = File.join(Dir.tmpdir(), File.basename(filename))
60
+ # puts 'fname2=' + fname2
61
+ # puts 'merged_file_array=' + merge.inspect
62
+ File.open(fname2, "w") do |f|
63
+ merge.each do |m|
64
+ puts "merging #{m} into #{filename}"
65
+ f.write File.open(m, 'r') { |mo| mo.read }
66
+ f.write "\n\n"
67
+ end
68
+ end
69
+ fname2
70
+ end
71
+
72
+ def add_sw_params(hash_to_send)
73
+ # todo: remove secret key?? Can use worker service from within a worker without it now
74
+ hash_to_send["sw_access_key"] = self.access_key
75
+ hash_to_send["sw_secret_key"] = self.secret_key
76
+ end
77
+
78
+ # class_name: The class name of a previously upload class, eg: MySuperWorker
79
+ # data: Arbitrary hash of your own data that your task will need to run.
80
+ def queue(class_name, data={})
81
+ puts "Queuing #{class_name}"
82
+ if !data.is_a?(Array)
83
+ data = [data]
84
+ end
85
+ p data
86
+ hash_to_send = {}
87
+ hash_to_send["payload"] = data
88
+ hash_to_send["class_name"] = class_name
89
+ add_sw_params(hash_to_send)
90
+ if defined?(RAILS_ENV)
91
+ hash_to_send["rails_env"] = RAILS_ENV
92
+ end
93
+ return queue_raw(class_name, hash_to_send)
94
+
95
+ end
96
+
97
+ def queue_raw(class_name, data={})
98
+ params = nil
99
+ hash_to_send = data
100
+ hash_to_send["class_name"] = class_name
101
+ ret = post("queue/add", hash_to_send)
102
+ ret
103
+
104
+ end
105
+
106
+
107
+ #
108
+ # schedule: hash of scheduling options that can include:
109
+ # Required:
110
+ # - start_at: Time of first run - DateTime or Time object.
111
+ # Optional:
112
+ # - run_every: Time in seconds between runs. If ommitted, task will only run once.
113
+ # - delay_type: Fixed Rate or Fixed Delay. Default is fixed_delay.
114
+ # - end_at: Scheduled task will stop running after this date (optional, if ommitted, runs forever or until cancelled)
115
+ # - run_times: Task will run exactly :run_times. For instance if :run_times is 5, then the task will run 5 times.
116
+ #
117
+ def schedule(class_name, data, schedule)
118
+ puts "Scheduling #{class_name}"
119
+ raise "Schedule must be a hash." if !schedule.is_a? Hash
120
+ # if !data.is_a?(Array)
121
+ # data = [data]
122
+ # end
123
+ hash_to_send = {}
124
+ hash_to_send["payload"] = data
125
+ hash_to_send["class_name"] = class_name
126
+ hash_to_send["schedule"] = schedule
127
+ add_sw_params(hash_to_send)
128
+ # puts 'about to send ' + hash_to_send.inspect
129
+ ret = post("scheduler/schedule", hash_to_send)
130
+ ret
131
+ end
132
+
133
+ def cancel_schedule(scheduled_task_id)
134
+ raise "Must include a schedule id." if scheduled_task_id.blank?
135
+ hash_to_send = {}
136
+ hash_to_send["scheduled_task_id"] = scheduled_task_id
137
+ ret = post("scheduler/cancel", hash_to_send)
138
+ ret
139
+ end
140
+
141
+ def get_schedules()
142
+ hash_to_send = {}
143
+ ret = get("scheduler/list", hash_to_send)
144
+ ret
145
+ end
146
+
147
+ def status(task_id)
148
+ data = {"task_id"=>task_id}
149
+ ret = get("task/status", data)
150
+ ret
151
+ end
152
+
153
+ def schedule_status(schedule_id)
154
+ data = {"schedule_id"=>schedule_id}
155
+ ret = get("scheduler/status", data)
156
+ ret
157
+ end
158
+
159
+ def log(task_id)
160
+ data = {"task_id"=>task_id}
161
+ ret = get("task/log", data)
162
+ # puts 'ret=' + ret.inspect
163
+ # ret["log"] = Base64.decode64(ret["log"])
164
+ ret
165
+ end
166
+
167
+
168
+ end
169
+
170
+ end
@@ -1,3 +1,6 @@
1
+ # UsedInWorker can be included in classes that you are merging in order to get some of the SimpleWorker features into that class.
2
+ # For instance, you can use the log() method and it will be logged to the SimpleWorker logs.
3
+
1
4
  module SimpleWorker
2
5
  module UsedInWorker
3
6
 
data/rails/init.rb ADDED
File without changes
@@ -0,0 +1,4 @@
1
+
2
+
3
+ require_relative 'models/model_1.rb'
4
+
data/test/test_base.rb CHANGED
@@ -1,34 +1,38 @@
1
1
  require 'test/unit'
2
2
  require 'yaml'
3
3
  begin
4
- require File.join(File.dirname(__FILE__), '../lib/simple_worker')
4
+ require File.join(File.dirname(__FILE__), '../lib/simple_worker')
5
5
  rescue Exception => ex
6
- puts ex.message
7
- require 'simple_worker'
6
+ puts ex.message
7
+ require 'simple_worker'
8
8
  end
9
- require File.join(File.dirname(__FILE__), "./test_worker")
10
- require File.join(File.dirname(__FILE__), "./test_worker_2")
11
- require File.join(File.dirname(__FILE__), "./test_worker_3")
9
+ require_relative "test_worker"
10
+ require_relative "test_worker_2"
11
+ require_relative "test_worker_3"
12
12
 
13
13
  class TestBase < Test::Unit::TestCase
14
14
 
15
- def setup
16
- @config = YAML::load(File.open(File.expand_path("~/.test-configs/simple_worker.yml")))
17
- #puts @config.inspect
18
- @access_key = @config['simple_worker']['access_key']
19
- @secret_key = @config['simple_worker']['secret_key']
15
+ def setup
16
+ @config = YAML::load(File.open(File.expand_path("~/.test_configs/simple_worker.yml")))
17
+ #puts @config.inspect
18
+ @access_key = @config['simple_worker']['access_key']
19
+ @secret_key = @config['simple_worker']['secret_key']
20
20
 
21
- @worker = SimpleWorker::Service.new(@access_key, @secret_key)
22
- @worker.host = "http://localhost:3000/api/"
21
+ # new style
22
+ SimpleWorker.configure do |config|
23
+ config.access_key = @access_key
24
+ config.secret_key = @secret_key
25
+ # config.host = "http://localhost:3000/api/"
26
+ config.global_attributes["db_user"] = "sa"
27
+ config.global_attributes["db_pass"] = "pass"
28
+ config.database = {
29
+ :adapter => "mysql2",
30
+ :host => "localhost",
31
+ :database => "appdb",
32
+ :username => "appuser",
33
+ :password => "secret"
34
+ }
23
35
 
24
- # new style
25
- SimpleWorker.configure do |config|
26
- config.access_key = @access_key
27
- config.secret_key = @secret_key
28
- config.host = "http://localhost:3000/api/"
29
- config.global_attributes["db_user"] = "sa"
30
- config.global_attributes["db_pass"] = "pass"
31
-
32
- end
33
36
  end
37
+ end
34
38
  end
@@ -1,18 +1,16 @@
1
-
2
-
3
1
  require_relative 'test_base'
4
2
 
5
3
  class SimpleWorkerTests < TestBase
6
4
 
7
5
 
8
- def test_new_worker_style
9
- # Add something to queue, get task ID back
10
- tw = TestWorker2.new
11
- tw.s3_key = "active style runner"
12
- tw.times = 3
13
- tw.x = true
6
+ def test_new_worker_style
7
+ # Add something to queue, get task ID back
8
+ tw = TestWorker2.new
9
+ tw.s3_key = "active style runner"
10
+ tw.times = 3
11
+ tw.x = true
14
12
 
15
- # schedule up a task
13
+ # schedule up a task
16
14
  # start_at = 10.seconds.since
17
15
  # response_hash_single = tw.schedule(:start_at=>start_at, :run_every=>30, :run_times=>3)
18
16
  # puts 'response_hash=' + response_hash_single.inspect
@@ -21,93 +19,39 @@ class SimpleWorkerTests < TestBase
21
19
  # puts "status #{i}: " + tw.schedule_status.inspect
22
20
  # end
23
21
 
24
- # queue up a task
25
- puts 'queuing ' + tw.inspect
26
- response_hash_single = tw.queue
22
+ # queue up a task
23
+ puts 'queuing ' + tw.inspect
24
+ response_hash_single = tw.queue
27
25
 
28
26
 
29
- puts 'response_hash=' + response_hash_single.inspect
30
- puts 'task_set_id=' + tw.task_set_id
31
- puts 'task_id=' + tw.task_id
32
- 10.times do |i|
33
- puts "status #{i}: " + tw.status.inspect
34
- break if tw.status["status"] == "complete"
35
- sleep 2
36
- end
27
+ puts 'response_hash=' + response_hash_single.inspect
28
+ puts 'task_set_id=' + tw.task_set_id
29
+ puts 'task_id=' + tw.task_id
30
+ 10.times do |i|
31
+ puts "status #{i}: " + tw.status.inspect
32
+ break if tw.status["status"] == "complete"
33
+ sleep 2
34
+ end
37
35
 
38
- assert tw.status["status"] == "complete"
36
+ assert tw.status["status"] == "complete"
39
37
 
40
- end
38
+ end
41
39
 
42
- def test_global_attributes
43
- worker = TestWorker3.new
44
- worker.run_local
40
+ def test_global_attributes
41
+ worker = TestWorker3.new
42
+ worker.run_local
45
43
 
46
- puts 'worker=' + worker.inspect
44
+ puts 'worker=' + worker.inspect
47
45
 
48
- assert_equal "sa", worker.db_user
49
- assert_equal "pass", worker.db_pass
50
- assert_equal 123, worker.x
46
+ assert_equal "sa", worker.db_user
47
+ assert_equal "pass", worker.db_pass
48
+ assert_equal 123, worker.x
49
+
50
+ end
51
+
52
+ def test_require_relative_merge
51
53
 
52
- end
53
- #
54
- #
55
- # def test_queue
56
- #
57
- #
58
- # # Upload latest runner code
59
- # @worker.upload(File.join(File.dirname(__FILE__), "./test_worker.rb"), "TestWorker")
60
- #
61
- # # Add something to queue, get task ID back
62
- # # Single task
63
- # response_hash_single = @worker.queue("TestWorker", {"s3_key"=>"single runner", "times"=>10})
64
- #
65
- # # task set
66
- # response_hash = @worker.queue("TestWorker", [{"id"=>"local_id", "s3_key"=>"some key", "times"=>4}, {"s3_key"=>"some key2", "times"=>3}, {"s3_key"=>"some key", "times"=>2}])
67
- #
68
- # # Check status
69
- # tasks = response_hash["tasks"]
70
- # puts 'tasks.size=' + tasks.size.to_s
71
- # while tasks.size > 0
72
- # tasks.each do |t|
73
- # puts "t=" + t.inspect
74
- # status_response = @worker.status(t["task_id"])
75
- # puts 'status for ' + t["task_id"] + ' = ' + status_response["status"]
76
- # if status_response["status"] == "complete" || status_response["status"] == "error" || status_response["status"] == "cancelled"
77
- # tasks.delete(t)
78
- # end
79
- # end
80
- # end
81
- #
82
- # # lets try to get the log now too
83
- # task_id = response_hash_single["tasks"][0]["task_id"]
84
- # puts 'task_id=' + task_id
85
- # status_with_log = @worker.log(task_id)
86
- # puts 'log=' + status_with_log.inspect
87
- #
88
- # end
89
- #
90
- # def test_scheduled
91
- #
92
- # # Upload latest runner code
93
- # @worker.upload(File.join(File.dirname(__FILE__), "./scheduled_worker.rb"), "ScheduledWorker")
94
- #
95
- # start_at = 10.seconds.since
96
- # #start_at = start_at.gmtime # testing different timezone
97
- # puts 'start_at =' + start_at.inspect
98
- # response_hash = @worker.schedule("ScheduledWorker", {"msg"=>"One time test."}, {:start_at=>start_at})
99
- # puts 'response_hash=' + response_hash.inspect
100
- #
101
- # start_at = 10.seconds.since
102
- # response_hash = @worker.schedule("ScheduledWorker", {"msg"=>"Run times test"}, {:start_at=>start_at, :run_every=>30, :run_times=>3})
103
- # puts 'response_hash=' + response_hash.inspect
104
- #
105
- # start_at = 10.seconds.since
106
- # end_at = 2.minutes.since
107
- # response_hash = @worker.schedule("ScheduledWorker", {"msg"=>"End at test"}, {:start_at=>start_at, :run_every=>30, :end_at=>end_at, :run_times=>20})
108
- # puts 'response_hash=' + response_hash.inspect
109
- #
110
- # end
111
54
 
55
+ end
112
56
  end
113
57
 
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 3
8
- - 15
9
- version: 0.3.15
8
+ - 16
9
+ version: 0.3.16
10
10
  platform: ruby
11
11
  authors:
12
12
  - Travis Reeder
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-11-18 00:00:00 -08:00
17
+ date: 2010-12-29 00:00:00 -08:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -39,12 +39,17 @@ extensions: []
39
39
  extra_rdoc_files:
40
40
  - README.markdown
41
41
  files:
42
+ - lib/rails2_init.rb
43
+ - lib/railtie.rb
42
44
  - lib/simple_worker.rb
43
45
  - lib/simple_worker/base.rb
44
46
  - lib/simple_worker/config.rb
47
+ - lib/simple_worker/service.rb
45
48
  - lib/simple_worker/used_in_worker.rb
49
+ - rails/init.rb
46
50
  - README.markdown
47
51
  - test/models/model_1.rb
52
+ - test/requiring_worker.rb
48
53
  - test/scheduled_worker.rb
49
54
  - test/second_worker.rb
50
55
  - test/test_base.rb
@@ -87,6 +92,7 @@ specification_version: 3
87
92
  summary: Classified
88
93
  test_files:
89
94
  - test/models/model_1.rb
95
+ - test/requiring_worker.rb
90
96
  - test/scheduled_worker.rb
91
97
  - test/second_worker.rb
92
98
  - test/test_base.rb