iron_worker 2.1.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.
- data/README.markdown +72 -0
- data/VERSION.yml +5 -0
- data/lib/generators/iron_worker/iron_worker_generator.rb +13 -0
- data/lib/iron_worker.rb +49 -0
- data/lib/iron_worker/api.rb +242 -0
- data/lib/iron_worker/base.rb +432 -0
- data/lib/iron_worker/config.rb +265 -0
- data/lib/iron_worker/rails2_init.rb +8 -0
- data/lib/iron_worker/railtie.rb +16 -0
- data/lib/iron_worker/server/overrides.rb +199 -0
- data/lib/iron_worker/server/runner.rb +80 -0
- data/lib/iron_worker/service.rb +553 -0
- data/lib/iron_worker/uber_client.rb +117 -0
- data/lib/iron_worker/used_in_worker.rb +11 -0
- data/lib/iron_worker/utils.rb +11 -0
- data/rails/init.rb +0 -0
- metadata +105 -0
data/README.markdown
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
Getting Started
|
2
|
+
===============
|
3
|
+
|
4
|
+
[Sign up for a IronWorker account][1], it's free to try!
|
5
|
+
|
6
|
+
[1]: http://www.iron.io/
|
7
|
+
|
8
|
+
Install IronWorker Gem
|
9
|
+
------------------------
|
10
|
+
|
11
|
+
gem install iron_worker
|
12
|
+
|
13
|
+
Configure IronWorker
|
14
|
+
----------------------
|
15
|
+
|
16
|
+
You really just need your token, which you can get [here][2]
|
17
|
+
[2]: http://hud.iron.io/tokens
|
18
|
+
|
19
|
+
IronWorker.configure do |config|
|
20
|
+
config.token = TOKEN
|
21
|
+
config.project_id = MY_PROJECT_ID
|
22
|
+
end
|
23
|
+
|
24
|
+
Write a Worker
|
25
|
+
--------------
|
26
|
+
|
27
|
+
Here's an example worker that sends an email:
|
28
|
+
|
29
|
+
require 'iron_worker'
|
30
|
+
|
31
|
+
class HelloWorker < IronWorker::Base
|
32
|
+
|
33
|
+
attr_accessor :name
|
34
|
+
|
35
|
+
# This is the method that will be run
|
36
|
+
def run
|
37
|
+
puts "Hello #{name}!"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
Test It Locally
|
42
|
+
---------------
|
43
|
+
|
44
|
+
Let's say someone does something in your app and you want to send an email about it.
|
45
|
+
|
46
|
+
worker = HelloWorker.new
|
47
|
+
worker.name = "Travis"
|
48
|
+
worker.run_local
|
49
|
+
|
50
|
+
Once you've got it working locally, the next step is to run it on the IronWorker cloud.
|
51
|
+
|
52
|
+
Queue up your Worker on the IronWorker Cloud
|
53
|
+
----------------------------------------------
|
54
|
+
|
55
|
+
Let's say someone does something in your app and you want to send an email about it.
|
56
|
+
|
57
|
+
worker = HelloWorker.new
|
58
|
+
worker.name = "Travis"
|
59
|
+
worker.queue
|
60
|
+
|
61
|
+
This will send it off to the IronWorker cloud.
|
62
|
+
|
63
|
+
Full Documentation
|
64
|
+
-----------------
|
65
|
+
|
66
|
+
Now that you've got your first worker running, be sure to [check out the full documentation](http://docs.iron.io).
|
67
|
+
IronWorker can do so much more!
|
68
|
+
|
69
|
+
Discussion Group
|
70
|
+
----------------------
|
71
|
+
|
72
|
+
Join the discussion group at: https://groups.google.com/forum/#!forum/ironworker-users
|
data/VERSION.yml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
class IronWorkerGenerator < Rails::Generators::NamedBase
|
2
|
+
source_root File.expand_path("../templates", __FILE__)
|
3
|
+
|
4
|
+
desc "Creates a new skeleton worker - NAME is camelized"
|
5
|
+
def create_worker_file
|
6
|
+
# file_name needs to be classified
|
7
|
+
@camel = file_name.camelize
|
8
|
+
if not File.directory? "#{Rails.root}/app/workers"
|
9
|
+
Dir.mkdir "#{Rails.root}/app/workers"
|
10
|
+
end
|
11
|
+
template "template_worker.erb", "app/workers/#{file_name}.rb"
|
12
|
+
end
|
13
|
+
end
|
data/lib/iron_worker.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative 'iron_worker/utils'
|
2
|
+
require_relative 'iron_worker/service'
|
3
|
+
require_relative 'iron_worker/base'
|
4
|
+
require_relative 'iron_worker/config'
|
5
|
+
require_relative 'iron_worker/used_in_worker'
|
6
|
+
|
7
|
+
|
8
|
+
module IronWorker
|
9
|
+
@@logger = Logger.new(STDOUT)
|
10
|
+
@@logger.level = Logger::INFO
|
11
|
+
|
12
|
+
|
13
|
+
class << self
|
14
|
+
attr_accessor :config,
|
15
|
+
:service
|
16
|
+
|
17
|
+
def configure()
|
18
|
+
yield(config)
|
19
|
+
if config && config.token
|
20
|
+
IronWorker.service ||= Service.new(config.token, :config=>config)
|
21
|
+
else
|
22
|
+
@@logger.warn "No token specified in configure, be sure to set it!"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def config
|
27
|
+
@config ||= Config.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def logger
|
31
|
+
@@logger
|
32
|
+
end
|
33
|
+
|
34
|
+
def api_version
|
35
|
+
2
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
if defined?(Rails)
|
42
|
+
# puts 'Rails=' + Rails.inspect
|
43
|
+
# puts 'vers=' + Rails::VERSION::MAJOR.inspect
|
44
|
+
if Rails::VERSION::MAJOR == 2
|
45
|
+
require_relative 'iron_worker/rails2_init.rb'
|
46
|
+
else
|
47
|
+
require_relative 'iron_worker/railtie'
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,242 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
require_relative 'uber_client'
|
3
|
+
|
4
|
+
module IronWorker
|
5
|
+
|
6
|
+
class RequestError < StandardError
|
7
|
+
def initialize(msg, options={})
|
8
|
+
super(msg)
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def status
|
13
|
+
@options[:status]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Api
|
18
|
+
|
19
|
+
module Signatures
|
20
|
+
|
21
|
+
|
22
|
+
def self.generate_timestamp(gmtime)
|
23
|
+
return gmtime.strftime("%Y-%m-%dT%H:%M:%SZ")
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def self.generate_signature(operation, timestamp, secret_key)
|
28
|
+
my_sha_hmac = Digest::HMAC.digest(operation + timestamp, secret_key, Digest::SHA1)
|
29
|
+
my_b64_hmac_digest = Base64.encode64(my_sha_hmac).strip
|
30
|
+
return my_b64_hmac_digest
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def self.hash_to_s(hash)
|
35
|
+
str = ""
|
36
|
+
hash.sort.each { |a| str+= "#{a[0]}#{a[1]}" }
|
37
|
+
#removing all characters that could differ after parsing with rails
|
38
|
+
return str.delete "\"\/:{}[]\' T"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Subclass must define:
|
43
|
+
# host: endpoint url for service
|
44
|
+
class Client
|
45
|
+
|
46
|
+
attr_accessor :scheme, :host, :port, :token, :version, :config
|
47
|
+
|
48
|
+
def initialize(host, token, options={})
|
49
|
+
@config = options[:config]
|
50
|
+
@scheme = options[:scheme] || @config.scheme || "https"
|
51
|
+
@host = options[:host] || @config.host || host
|
52
|
+
@port = options[:port] || @config.port || 443
|
53
|
+
@token = options[:token] || @config.token || token
|
54
|
+
@version = options[:version]
|
55
|
+
#@logger = options[:logger]
|
56
|
+
|
57
|
+
@base_url = "#{@scheme}://#{@host}:#{@port}/#{@version}"
|
58
|
+
|
59
|
+
@uber_client = Uber::Client.new
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def base_url
|
65
|
+
@base_url
|
66
|
+
end
|
67
|
+
|
68
|
+
def url(command_path)
|
69
|
+
# @logger.debug "url: " + url.to_s
|
70
|
+
"/#{command_path}"
|
71
|
+
end
|
72
|
+
|
73
|
+
def url_full(command_path)
|
74
|
+
url = "#{base_url}/#{command_path}"
|
75
|
+
# @logger.debug "url: " + url.to_s
|
76
|
+
url
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def common_req_hash
|
81
|
+
{
|
82
|
+
:headers=>{"Content-Type" => 'application/json',
|
83
|
+
"Authorization"=>"OAuth #{@token}",
|
84
|
+
"User-Agent"=>"IronWorker Ruby Client"}
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
def process_ex(ex)
|
89
|
+
logger.error "EX #{ex.class.name}: #{ex.message}"
|
90
|
+
body = ex.http_body
|
91
|
+
logger.debug 'EX http_code: ' + ex.http_code.to_s
|
92
|
+
logger.debug 'EX BODY=' + body.to_s
|
93
|
+
decoded_ex = JSON.parse(body)
|
94
|
+
exception = Exception.new(ex.message + ": " + decoded_ex["msg"])
|
95
|
+
exception.set_backtrace(decoded_ex["backtrace"].split(",")) if decoded_ex["backtrace"]
|
96
|
+
raise exception
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def check_response(response, options={})
|
101
|
+
# response.code # http status code
|
102
|
+
#response.time # time in seconds the request took
|
103
|
+
#response.headers # the http headers
|
104
|
+
#response.headers_hash # http headers put into a hash
|
105
|
+
#response.body # the response body
|
106
|
+
status = response.code
|
107
|
+
body = response.body
|
108
|
+
# todo: check content-type == application/json before parsing
|
109
|
+
logger.debug "response code=" + status.to_s
|
110
|
+
logger.debug "response body=" + body.inspect
|
111
|
+
res = nil
|
112
|
+
unless options[:parse] == false
|
113
|
+
res = JSON.parse(body)
|
114
|
+
end
|
115
|
+
if status < 400
|
116
|
+
|
117
|
+
else
|
118
|
+
raise IronWorker::RequestError.new((res ? "#{status}: #{res["msg"]}" : "#{status} Error! parse=false so no msg"), :status=>status)
|
119
|
+
end
|
120
|
+
res || body
|
121
|
+
end
|
122
|
+
|
123
|
+
def get(method, params={}, options={})
|
124
|
+
full_url = url_full(method)
|
125
|
+
#all_params = add_params(method, params)
|
126
|
+
#url_plus_params = append_params(full_url, all_params)
|
127
|
+
logger.debug 'get url=' + full_url
|
128
|
+
req_hash = common_req_hash
|
129
|
+
req_hash[:params] = params
|
130
|
+
response = @uber_client.get(full_url, req_hash) # could let typhoeus add params, using :params=>x
|
131
|
+
#response = @http_sess.request(:get, url_plus_params,
|
132
|
+
# {},
|
133
|
+
# {})
|
134
|
+
check_response(response, options)
|
135
|
+
body = response.body
|
136
|
+
parse_response(body, options)
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
def post_file(method, file, params={}, options={})
|
141
|
+
begin
|
142
|
+
data = add_params(method, params).to_json
|
143
|
+
url = url_full(method)
|
144
|
+
logger.debug "post_file url = " + url
|
145
|
+
logger.debug "data = " + data
|
146
|
+
logger.debug "params = " + params.inspect
|
147
|
+
logger.debug "options = " + options.inspect
|
148
|
+
# todo: replace with uber_client
|
149
|
+
parse_response(RestClient.post(append_params(url, add_params(method, params)), {:data => data, :file => file}, :content_type => 'application/json'), options)
|
150
|
+
rescue RestClient::Exception => ex
|
151
|
+
process_ex(ex)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def post(method, params={}, options={})
|
156
|
+
logger.debug "params = " + params.inspect
|
157
|
+
logger.debug "options = " + options.inspect
|
158
|
+
logger.debug "params.payload = " + params[:payload].inspect
|
159
|
+
logger.debug "token = "+ token.inspect
|
160
|
+
begin
|
161
|
+
url = url_full(method)
|
162
|
+
logger.debug 'post url=' + url
|
163
|
+
json = add_params(method, params).to_json
|
164
|
+
logger.debug 'body=' + json
|
165
|
+
req_hash = common_req_hash
|
166
|
+
req_hash[:body] = json
|
167
|
+
response = @uber_client.post(url, req_hash)
|
168
|
+
#response = @http_sess.post(url, json, {"Content-Type" => 'application/json'})
|
169
|
+
check_response(response)
|
170
|
+
logger.debug 'response: ' + response.inspect
|
171
|
+
body = response.body
|
172
|
+
parse_response(body, options)
|
173
|
+
rescue IronWorker::RequestError => ex
|
174
|
+
# let it throw, came from check_response
|
175
|
+
raise ex
|
176
|
+
rescue RestClient::Exception => ex
|
177
|
+
logger.warn("Exception in post! #{ex.message}")
|
178
|
+
logger.warn(ex.backtrace.join("\n"))
|
179
|
+
process_ex(ex)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
def put(method, body, options={})
|
185
|
+
begin
|
186
|
+
# todo: replace with uber_client
|
187
|
+
parse_response RestClient.put(url_full(method), add_params(method, body).to_json, headers), options
|
188
|
+
rescue RestClient::Exception => ex
|
189
|
+
process_ex(ex)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def delete(method, params={}, options={})
|
194
|
+
begin
|
195
|
+
# todo: replace with uber_client
|
196
|
+
parse_response RestClient.delete(append_params(url_full(method), add_params(method, params))), options
|
197
|
+
rescue RestClient::Exception => ex
|
198
|
+
process_ex(ex)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def add_params(command_path, hash)
|
203
|
+
extra_params = {'oauth' => token}
|
204
|
+
hash.merge!(extra_params)
|
205
|
+
end
|
206
|
+
|
207
|
+
def append_params(host, params)
|
208
|
+
host += "?"
|
209
|
+
i = 0
|
210
|
+
params.each_pair do |k, v|
|
211
|
+
#puts "k=#{k} v=#{v}"
|
212
|
+
host += "&" if i > 0
|
213
|
+
host += k + "=" + (v.is_a?(String) ? CGI.escape(v) : v.to_s)
|
214
|
+
i +=1
|
215
|
+
end
|
216
|
+
return host
|
217
|
+
end
|
218
|
+
|
219
|
+
def headers
|
220
|
+
user_agent = "IronWorker Ruby Client"
|
221
|
+
headers = {'User-Agent' => user_agent}
|
222
|
+
end
|
223
|
+
|
224
|
+
def parse_response(response, options={})
|
225
|
+
#puts 'PARSE RESPONSE: ' + response.to_s
|
226
|
+
unless options[:parse] == false
|
227
|
+
begin
|
228
|
+
return JSON.parse(response.to_s)
|
229
|
+
rescue => ex
|
230
|
+
puts 'parse_response: response that caused error = ' + response.to_s
|
231
|
+
raise ex
|
232
|
+
end
|
233
|
+
else
|
234
|
+
response
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
@@ -0,0 +1,432 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'base64'
|
3
|
+
|
4
|
+
module IronWorker
|
5
|
+
|
6
|
+
class Base
|
7
|
+
|
8
|
+
attr_accessor :task_set_id, :task_id, :schedule_id
|
9
|
+
attr_reader :response
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :subclass, :caller_file
|
13
|
+
@merged = {}
|
14
|
+
@merged_workers = {}
|
15
|
+
@merged_gems = {}
|
16
|
+
@merged_mailers = {}
|
17
|
+
@merged_folders = {}
|
18
|
+
@unmerged = {}
|
19
|
+
@unmerged_gems = {}
|
20
|
+
|
21
|
+
def reset!
|
22
|
+
@merged = {}
|
23
|
+
@merged_workers = {}
|
24
|
+
@merged_gems = {}
|
25
|
+
@merged_mailers = {}
|
26
|
+
@merged_folders = {}
|
27
|
+
@unmerged = {}
|
28
|
+
@unmerged_gems = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def inherited(subclass)
|
32
|
+
subclass.reset!
|
33
|
+
|
34
|
+
caller_file = caller[0][0...(caller[0].index(":in"))]
|
35
|
+
caller_file = caller_file[0...(caller_file.rindex(":"))]
|
36
|
+
subclass.instance_variable_set(:@caller_file, caller_file)
|
37
|
+
|
38
|
+
super
|
39
|
+
end
|
40
|
+
|
41
|
+
# merges the specified gem.
|
42
|
+
def merge_gem(gem_name, options={})
|
43
|
+
gem_info = IronWorker::MergeHelper.create_gem_info(gem_name, options)
|
44
|
+
@merged_gems[gem_name.to_s] = gem_info
|
45
|
+
reqs = gem_info[:require].is_a?(Array) ? gem_info[:require] : [gem_info[:require]]
|
46
|
+
reqs.each do |r|
|
47
|
+
r2 = "#{gem_info[:path]}/lib/#{r}"
|
48
|
+
begin
|
49
|
+
IronWorker.logger.debug 'requiring ' + r2
|
50
|
+
require r2
|
51
|
+
rescue LoadError=>ex
|
52
|
+
IronWorker.logger.error "Error requiring gem #{r}: #{ex.message}"
|
53
|
+
raise "Gem #{gem_name} was found, but we could not load the file '#{r2}'. You may need to use :require=>x.........."
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def unmerge_gem(gem_name)
|
60
|
+
#gem_info = {:name=>gem_name}
|
61
|
+
#@unmerged_gems[gem_name.to_s] = gem_info
|
62
|
+
gs = gem_name.to_s
|
63
|
+
gem_info = {:name=>gs}
|
64
|
+
@unmerged_gems[gs] = gem_info
|
65
|
+
@merged_gems.delete(gs)
|
66
|
+
end
|
67
|
+
|
68
|
+
#merge action_mailer mailers
|
69
|
+
def merge_mailer(mailer, params={})
|
70
|
+
f2 = IronWorker::MergeHelper.check_for_file(mailer, @caller_file)
|
71
|
+
basename = File.basename(mailer, f2[:extname])
|
72
|
+
path_to_templates = params[:path_to_templates] || File.join(Rails.root, "app/views/#{basename}")
|
73
|
+
@merged_mailers[basename] = {:name=>basename, :path_to_templates=>path_to_templates, :filename => f2[:path]}.merge!(params)
|
74
|
+
end
|
75
|
+
|
76
|
+
def merge_folder(path)
|
77
|
+
files = []
|
78
|
+
#puts "caller_file=" + caller_file
|
79
|
+
if path[0, 1] == '/'
|
80
|
+
abs_dir = path
|
81
|
+
else # relative
|
82
|
+
abs_dir = File.join(File.dirname(caller_file), path)
|
83
|
+
end
|
84
|
+
#puts 'abs_dir=' + abs_dir
|
85
|
+
raise "Folder not found for merge_folder #{path}!" unless File.directory?(abs_dir)
|
86
|
+
rbfiles = File.join(abs_dir, "*.rb")
|
87
|
+
Dir[rbfiles].each do |f|
|
88
|
+
#f2 = check_for_file(f)
|
89
|
+
#puts "f2=#{f2}"
|
90
|
+
merge(f)
|
91
|
+
#files << f
|
92
|
+
#@merged[f]
|
93
|
+
end
|
94
|
+
#@merged_folders[path] = files unless files.empty?
|
95
|
+
#IronWorker.logger.info "Merged folders! #{@merged_folders.inspect}"
|
96
|
+
end
|
97
|
+
|
98
|
+
# merges the specified file.
|
99
|
+
#
|
100
|
+
# Example: merge 'models/my_model'
|
101
|
+
def merge(f)
|
102
|
+
f2 = IronWorker::MergeHelper.check_for_file(f, @caller_file)
|
103
|
+
fbase = f2[:basename]
|
104
|
+
ret = f2
|
105
|
+
@merged[fbase] = ret
|
106
|
+
ret
|
107
|
+
end
|
108
|
+
|
109
|
+
# Opposite of merge, this will omit the files you specify from being merged in. Useful in Rails apps
|
110
|
+
# where a lot of things are auto-merged by default like your models.
|
111
|
+
def unmerge(f)
|
112
|
+
f2 = IronWorker::MergeHelper.check_for_file(f, @caller_file)
|
113
|
+
fbase = f2[:basename]
|
114
|
+
@unmerged[fbase] = f2
|
115
|
+
@merged.delete(fbase)
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
# Use this to merge in other workers. These are treated differently the normal merged files because
|
120
|
+
# they will be uploaded separately and treated as distinctly separate workers.
|
121
|
+
#
|
122
|
+
# file: This is the path to the file, just like merge.
|
123
|
+
# class_name: eg: 'MyWorker'.
|
124
|
+
def merge_worker(file, class_name)
|
125
|
+
# puts 'merge_worker in ' + self.name
|
126
|
+
ret = merge(file)
|
127
|
+
ret[:class_name] = class_name
|
128
|
+
#[File.expand_path(file), class_name]
|
129
|
+
@merged_workers[file] = ret
|
130
|
+
ret
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
def log(str)
|
136
|
+
puts str.to_s
|
137
|
+
end
|
138
|
+
|
139
|
+
def user_dir
|
140
|
+
"./"
|
141
|
+
end
|
142
|
+
|
143
|
+
def set_progress(hash)
|
144
|
+
puts 'set_progress: ' + hash.inspect
|
145
|
+
end
|
146
|
+
|
147
|
+
def who_am_i?
|
148
|
+
return self.class.name
|
149
|
+
end
|
150
|
+
|
151
|
+
def uploaded?
|
152
|
+
self.class.instance_variable_defined?(:@uploaded) && self.class.instance_variable_get(:@uploaded)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Call this if you want to run locally and get some extra features from this gem like global attributes.
|
156
|
+
def run_local
|
157
|
+
# puts 'run_local'
|
158
|
+
set_auto_attributes
|
159
|
+
init_database
|
160
|
+
init_mailer
|
161
|
+
begin
|
162
|
+
run
|
163
|
+
rescue => ex
|
164
|
+
if self.respond_to?(:rescue_all)
|
165
|
+
rescue_all(ex)
|
166
|
+
else
|
167
|
+
raise ex
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def init_mailer
|
173
|
+
if IronWorker.config.mailer
|
174
|
+
require 'action_mailer'
|
175
|
+
ActionMailer::Base.raise_delivery_errors = true
|
176
|
+
ActionMailer::Base.smtp_settings = (IronWorker.config.mailer)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def init_database
|
181
|
+
if IronWorker.config.database
|
182
|
+
require 'active_record'
|
183
|
+
if !ActiveRecord::Base.connected?
|
184
|
+
ActiveRecord::Base.establish_connection(IronWorker.config.database)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def set_auto_attributes
|
190
|
+
set_global_attributes
|
191
|
+
end
|
192
|
+
|
193
|
+
def set_global_attributes
|
194
|
+
return unless IronWorker.config
|
195
|
+
ga = IronWorker.config.global_attributes
|
196
|
+
if ga && ga.size > 0
|
197
|
+
ga.each_pair do |k, v|
|
198
|
+
# puts "k=#{k} v=#{v}"
|
199
|
+
if self.respond_to?(k)
|
200
|
+
self.send("#{k}=", v)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def enqueue(options={})
|
207
|
+
queue(options)
|
208
|
+
end
|
209
|
+
|
210
|
+
# Call this to queue up your job to IronWorker cloud.
|
211
|
+
# options:
|
212
|
+
# :priority => 0, 1 or 2. Default is 0.
|
213
|
+
# :recursive => true/false. Default is false. If you queue up a worker that is the same class as the currently
|
214
|
+
# running worker, it will be rejected unless you set this explicitly so we know you meant to do it.
|
215
|
+
def queue(options={})
|
216
|
+
# puts 'in queue'
|
217
|
+
set_auto_attributes
|
218
|
+
upload_if_needed(options)
|
219
|
+
|
220
|
+
response = IronWorker.service.queue(self.class.name, sw_get_data, options)
|
221
|
+
IronWorker.service.logger.debug 'queue response=' + response.inspect
|
222
|
+
@response = response
|
223
|
+
@task_id = response["tasks"][0]["id"]
|
224
|
+
response
|
225
|
+
end
|
226
|
+
|
227
|
+
# Receive the status of your worker.
|
228
|
+
def status
|
229
|
+
check_service
|
230
|
+
if task_id
|
231
|
+
task_status
|
232
|
+
elsif schedule_id
|
233
|
+
schedule_status
|
234
|
+
else
|
235
|
+
raise "Queue or schedule before check status."
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def task_status
|
240
|
+
IronWorker.service.status(task_id)
|
241
|
+
end
|
242
|
+
|
243
|
+
def is_local?
|
244
|
+
!is_remote?
|
245
|
+
end
|
246
|
+
|
247
|
+
def is_remote?
|
248
|
+
false
|
249
|
+
end
|
250
|
+
|
251
|
+
# will return after job has completed or errored out.
|
252
|
+
# Returns status.
|
253
|
+
# todo: add a :timeout option
|
254
|
+
def wait_until_complete
|
255
|
+
check_service
|
256
|
+
IronWorker.service.wait_until_complete(self.task_id)
|
257
|
+
end
|
258
|
+
|
259
|
+
def upload
|
260
|
+
upload_if_needed
|
261
|
+
end
|
262
|
+
|
263
|
+
#
|
264
|
+
# schedule: hash of scheduling options that can include:
|
265
|
+
# Required:
|
266
|
+
# - start_at: Time of first run - DateTime or Time object.
|
267
|
+
# Optional:
|
268
|
+
# - run_every: Time in seconds between runs. If ommitted, task will only run once.
|
269
|
+
# - delay_type: Fixed Rate or Fixed Delay. Default is fixed_delay.
|
270
|
+
# - end_at: Scheduled task will stop running after this date (optional, if ommitted, runs forever or until cancelled)
|
271
|
+
# - run_times: Task will run exactly :run_times. For instance if :run_times is 5, then the task will run 5 times.
|
272
|
+
# - name: Provide a name for the schedule, defaults to class name. Use this if you want more than one schedule per worker class.
|
273
|
+
#
|
274
|
+
def schedule(schedule)
|
275
|
+
set_global_attributes
|
276
|
+
upload_if_needed(schedule)
|
277
|
+
|
278
|
+
response = IronWorker.service.schedule(self.class.name, sw_get_data, schedule)
|
279
|
+
IronWorker.service.logger.debug 'schedule response=' + response.inspect
|
280
|
+
@schedule_id = response["schedules"][0]["id"]
|
281
|
+
response
|
282
|
+
end
|
283
|
+
|
284
|
+
def schedule_status
|
285
|
+
IronWorker.service.schedule_status(schedule_id)
|
286
|
+
end
|
287
|
+
|
288
|
+
# Retrieves the log for this worker from the IronWorker service.
|
289
|
+
def get_log(options={})
|
290
|
+
IronWorker.service.get_log(task_id, options)
|
291
|
+
end
|
292
|
+
|
293
|
+
# Callbacks for developer
|
294
|
+
def before_upload
|
295
|
+
|
296
|
+
end
|
297
|
+
|
298
|
+
def after_upload
|
299
|
+
|
300
|
+
end
|
301
|
+
|
302
|
+
def before_run
|
303
|
+
|
304
|
+
end
|
305
|
+
|
306
|
+
def after_run
|
307
|
+
|
308
|
+
end
|
309
|
+
|
310
|
+
private
|
311
|
+
|
312
|
+
def gems_to_merge(merged_gems)
|
313
|
+
list_of_gems = {}
|
314
|
+
if merged_gems && merged_gems.size > 0
|
315
|
+
installed_gems = IronWorker.config.get_server_gems
|
316
|
+
merged_gems.each_pair do |k, gem|
|
317
|
+
gem.merge!({:merge=>(!installed_gems.find { |g| g["name"]==gem[:name] && g["version"]==gem[:version] })})
|
318
|
+
list_of_gems[gem[:name]] = gem # don't' need this if (list_of_gems.select { |k,g| g[:name]==gem[:name] }).empty?
|
319
|
+
end
|
320
|
+
IronWorker.logger.debug "#{list_of_gems.inspect}"
|
321
|
+
end
|
322
|
+
list_of_gems
|
323
|
+
end
|
324
|
+
|
325
|
+
def check_service
|
326
|
+
raise "IronWorker configuration not set." unless IronWorker.service
|
327
|
+
end
|
328
|
+
|
329
|
+
def self.extract_superclasses_merges(worker, merged)
|
330
|
+
subclass = worker.class
|
331
|
+
rfile = subclass.instance_variable_get(:@caller_file) # Base.caller_file # File.expand_path(Base.subclass)
|
332
|
+
# puts 'subclass file=' + rfile.inspect
|
333
|
+
# puts 'subclass.name=' + subclass.name
|
334
|
+
superclass = subclass
|
335
|
+
# Also get merged from subclasses up to IronWorker::Base
|
336
|
+
while (superclass = superclass.superclass)
|
337
|
+
#puts 'superclass=' + superclass.name
|
338
|
+
break if superclass.name == IronWorker::Base.name
|
339
|
+
super_merged = superclass.instance_variable_get(:@merged)
|
340
|
+
#puts 'merging caller file: ' + superclass.instance_variable_get(:@caller_file).inspect
|
341
|
+
caller_to_add = superclass.instance_variable_get(:@caller_file)
|
342
|
+
fb = File.basename(caller_to_add)
|
343
|
+
r = {:name=>fb, :path=>caller_to_add}
|
344
|
+
super_merged[fb] = r
|
345
|
+
merged.merge!(super_merged)
|
346
|
+
#puts 'merged with superclass=' + merged.inspect
|
347
|
+
end
|
348
|
+
return merged, rfile, subclass
|
349
|
+
end
|
350
|
+
|
351
|
+
def self.extract_merged_workers(worker)
|
352
|
+
merged_workers = worker.class.instance_variable_get(:@merged_workers)
|
353
|
+
IronWorker.logger.debug "Looking for merged_workers in #{worker.class.name}: #{merged_workers.inspect}"
|
354
|
+
ret = {}
|
355
|
+
if merged_workers && merged_workers.size > 0
|
356
|
+
merged_workers.each_pair do |k, mw|
|
357
|
+
IronWorker.logger.debug "merged worker found in #{worker.class.name}: #{mw.inspect}"
|
358
|
+
ret[mw[:name]] = mw
|
359
|
+
end
|
360
|
+
end
|
361
|
+
ret
|
362
|
+
end
|
363
|
+
|
364
|
+
def upload_if_needed(options={})
|
365
|
+
check_service
|
366
|
+
IronWorker.service.check_config
|
367
|
+
|
368
|
+
before_upload
|
369
|
+
|
370
|
+
merged = self.class.instance_variable_get(:@merged)
|
371
|
+
|
372
|
+
# do merged_workers first because we need to get their subclasses and what not too
|
373
|
+
merged_workers = self.class.instance_variable_get(:@merged_workers)
|
374
|
+
if merged_workers && merged_workers.size > 0
|
375
|
+
IronWorker.logger.debug 'now uploading merged workers ' + merged_workers.inspect
|
376
|
+
merged_workers.each_pair do |mw, v|
|
377
|
+
IronWorker.logger.debug 'Instantiating and uploading ' + v.inspect
|
378
|
+
mw_instantiated = Kernel.const_get(v[:class_name]).new
|
379
|
+
mw_instantiated.upload
|
380
|
+
|
381
|
+
merged, rfile, subclass = IronWorker::Base.extract_superclasses_merges(mw_instantiated, merged)
|
382
|
+
merged.merge!(IronWorker::Base.extract_merged_workers(mw_instantiated))
|
383
|
+
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
if !uploaded?
|
388
|
+
unmerged = self.class.instance_variable_get(:@unmerged)
|
389
|
+
merged_gems = self.class.instance_variable_get(:@merged_gems)
|
390
|
+
merged_mailers = self.class.instance_variable_get(:@merged_mailers)
|
391
|
+
merged_folders = self.class.instance_variable_get(:@merged_folders)
|
392
|
+
merged, rfile, subclass = IronWorker::Base.extract_superclasses_merges(self, merged)
|
393
|
+
merged_mailers = merged_mailers.merge(IronWorker.config.mailers) if IronWorker.config.mailers
|
394
|
+
unless merged_gems.size == 0
|
395
|
+
merged_gems = gems_to_merge(merged_gems)
|
396
|
+
end
|
397
|
+
|
398
|
+
options_for_upload = {:merge=>merged, :unmerge=>unmerged, :merged_gems=>merged_gems, :merged_mailers=>merged_mailers, :merged_folders=>merged_folders}
|
399
|
+
options_for_upload.merge!(options)
|
400
|
+
IronWorker.service.upload(rfile, subclass.name, options_for_upload)
|
401
|
+
self.class.instance_variable_set(:@uploaded, true)
|
402
|
+
else
|
403
|
+
IronWorker.logger.debug 'Already uploaded for ' + self.class.name
|
404
|
+
end
|
405
|
+
|
406
|
+
after_upload
|
407
|
+
end
|
408
|
+
|
409
|
+
def sw_get_data
|
410
|
+
data = {}
|
411
|
+
|
412
|
+
payload = {}
|
413
|
+
# todo: should put these down a layer, eg: payload[:attributes]
|
414
|
+
self.instance_variables.each do |iv|
|
415
|
+
payload[iv] = instance_variable_get(iv)
|
416
|
+
end
|
417
|
+
data['class_name'] = self.class.name
|
418
|
+
data[:attr_encoded] = Base64.encode64(payload.to_json)
|
419
|
+
data[:file_name] = File.basename(self.class.instance_variable_get(:@caller_file))
|
420
|
+
if defined?(Rails)
|
421
|
+
data[:rails] = {}
|
422
|
+
data[:rails]['env'] = Rails.env
|
423
|
+
data[:rails]['version'] = Rails.version
|
424
|
+
end
|
425
|
+
config_data = IronWorker.config.get_atts_to_send
|
426
|
+
data[:sw_config] = config_data
|
427
|
+
return data
|
428
|
+
end
|
429
|
+
|
430
|
+
|
431
|
+
end
|
432
|
+
end
|