skynet 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. data/History.txt +49 -0
  2. data/Manifest.txt +84 -6
  3. data/README.txt +75 -64
  4. data/app_generators/skynet_install/skynet_install_generator.rb +14 -8
  5. data/app_generators/skynet_install/templates/migration.rb +1 -24
  6. data/app_generators/skynet_install/templates/skynet_config.rb +50 -0
  7. data/app_generators/skynet_install/templates/skynet_initializer.rb +1 -0
  8. data/app_generators/skynet_install/templates/{skynet_schema.sql → skynet_mysql_schema.sql} +1 -24
  9. data/bin/skynet +37 -10
  10. data/bin/skynet_install +5 -5
  11. data/bin/skynet_tuplespace_server +27 -19
  12. data/examples/dgrep/README +70 -0
  13. data/examples/dgrep/config/skynet_config.rb +26 -0
  14. data/examples/dgrep/data/shakespeare/README +2 -0
  15. data/examples/dgrep/data/shakespeare/poetry/loverscomplaint +381 -0
  16. data/examples/dgrep/data/shakespeare/poetry/rapeoflucrece +2199 -0
  17. data/examples/dgrep/data/shakespeare/poetry/sonnets +2633 -0
  18. data/examples/dgrep/data/shakespeare/poetry/various +640 -0
  19. data/examples/dgrep/data/shakespeare/poetry/venusandadonis +1423 -0
  20. data/examples/dgrep/data/testfile1.txt +1 -0
  21. data/examples/dgrep/data/testfile2.txt +1 -0
  22. data/examples/dgrep/data/testfile3.txt +1 -0
  23. data/examples/dgrep/data/testfile4.txt +1 -0
  24. data/examples/dgrep/lib/dgrep.rb +59 -0
  25. data/examples/dgrep/lib/mapreduce_test.rb +32 -0
  26. data/examples/dgrep/lib/most_common_words.rb +45 -0
  27. data/examples/dgrep/script/dgrep +75 -0
  28. data/examples/rails_mysql_example/README +66 -0
  29. data/examples/rails_mysql_example/Rakefile +10 -0
  30. data/examples/rails_mysql_example/app/controllers/application.rb +10 -0
  31. data/examples/rails_mysql_example/app/helpers/application_helper.rb +3 -0
  32. data/examples/rails_mysql_example/app/models/user.rb +21 -0
  33. data/examples/rails_mysql_example/app/models/user_favorite.rb +5 -0
  34. data/examples/rails_mysql_example/app/models/user_mailer.rb +12 -0
  35. data/examples/rails_mysql_example/app/views/user_mailer/welcome.erb +5 -0
  36. data/examples/rails_mysql_example/config/boot.rb +109 -0
  37. data/examples/rails_mysql_example/config/database.yml +42 -0
  38. data/examples/rails_mysql_example/config/environment.rb +59 -0
  39. data/examples/rails_mysql_example/config/environments/development.rb +18 -0
  40. data/examples/rails_mysql_example/config/environments/production.rb +19 -0
  41. data/examples/rails_mysql_example/config/environments/test.rb +22 -0
  42. data/examples/rails_mysql_example/config/initializers/inflections.rb +10 -0
  43. data/examples/rails_mysql_example/config/initializers/mime_types.rb +5 -0
  44. data/examples/rails_mysql_example/config/initializers/skynet.rb +1 -0
  45. data/examples/rails_mysql_example/config/routes.rb +35 -0
  46. data/examples/rails_mysql_example/config/skynet_config.rb +36 -0
  47. data/examples/rails_mysql_example/db/migrate/001_create_skynet_tables.rb +43 -0
  48. data/examples/rails_mysql_example/db/migrate/002_create_users.rb +16 -0
  49. data/examples/rails_mysql_example/db/migrate/003_create_user_favorites.rb +14 -0
  50. data/examples/rails_mysql_example/db/schema.rb +85 -0
  51. data/examples/rails_mysql_example/db/skynet_mysql_schema.sql +33 -0
  52. data/examples/rails_mysql_example/doc/README_FOR_APP +2 -0
  53. data/examples/rails_mysql_example/lib/tasks/rails_mysql_example.rake +20 -0
  54. data/examples/rails_mysql_example/public/.htaccess +40 -0
  55. data/examples/rails_mysql_example/public/404.html +30 -0
  56. data/examples/rails_mysql_example/public/422.html +30 -0
  57. data/examples/rails_mysql_example/public/500.html +30 -0
  58. data/examples/rails_mysql_example/public/dispatch.cgi +10 -0
  59. data/examples/rails_mysql_example/public/dispatch.fcgi +24 -0
  60. data/examples/rails_mysql_example/public/dispatch.rb +10 -0
  61. data/{log/debug.log → examples/rails_mysql_example/public/favicon.ico} +0 -0
  62. data/examples/rails_mysql_example/public/images/rails.png +0 -0
  63. data/examples/rails_mysql_example/public/index.html +277 -0
  64. data/examples/rails_mysql_example/public/javascripts/application.js +2 -0
  65. data/examples/rails_mysql_example/public/javascripts/controls.js +963 -0
  66. data/examples/rails_mysql_example/public/javascripts/dragdrop.js +972 -0
  67. data/examples/rails_mysql_example/public/javascripts/effects.js +1120 -0
  68. data/examples/rails_mysql_example/public/javascripts/prototype.js +4225 -0
  69. data/examples/rails_mysql_example/public/robots.txt +5 -0
  70. data/examples/rails_mysql_example/script/about +3 -0
  71. data/examples/rails_mysql_example/script/console +3 -0
  72. data/examples/rails_mysql_example/script/destroy +3 -0
  73. data/examples/rails_mysql_example/script/generate +3 -0
  74. data/examples/rails_mysql_example/script/performance/benchmarker +3 -0
  75. data/examples/rails_mysql_example/script/performance/profiler +3 -0
  76. data/examples/rails_mysql_example/script/performance/request +3 -0
  77. data/examples/rails_mysql_example/script/plugin +3 -0
  78. data/examples/rails_mysql_example/script/process/inspector +3 -0
  79. data/examples/rails_mysql_example/script/process/reaper +3 -0
  80. data/examples/rails_mysql_example/script/process/spawner +3 -0
  81. data/examples/rails_mysql_example/script/runner +3 -0
  82. data/examples/rails_mysql_example/script/server +3 -0
  83. data/examples/rails_mysql_example/test/fixtures/user_favorites.yml +9 -0
  84. data/examples/rails_mysql_example/test/fixtures/users.yml +11 -0
  85. data/examples/rails_mysql_example/test/test_helper.rb +38 -0
  86. data/examples/rails_mysql_example/test/unit/user_favorite_test.rb +8 -0
  87. data/examples/rails_mysql_example/test/unit/user_test.rb +8 -0
  88. data/extras/README +7 -0
  89. data/extras/init.d/skynet +87 -0
  90. data/extras/nagios/check_skynet.sh +121 -0
  91. data/extras/rails/controllers/skynet_controller.rb +43 -0
  92. data/extras/rails/views/skynet/index.rhtml +137 -0
  93. data/lib/skynet.rb +59 -1
  94. data/lib/skynet/mapreduce_helper.rb +2 -2
  95. data/lib/skynet/mapreduce_test.rb +32 -1
  96. data/lib/skynet/message_queue_adapters/mysql.rb +422 -539
  97. data/lib/skynet/message_queue_adapters/tuple_space.rb +45 -71
  98. data/lib/skynet/skynet_active_record_extensions.rb +22 -11
  99. data/lib/skynet/skynet_config.rb +54 -20
  100. data/lib/skynet/skynet_console.rb +4 -1
  101. data/lib/skynet/skynet_console_helper.rb +5 -1
  102. data/lib/skynet/skynet_debugger.rb +58 -4
  103. data/lib/skynet/skynet_job.rb +61 -24
  104. data/lib/skynet/skynet_launcher.rb +29 -3
  105. data/lib/skynet/skynet_logger.rb +11 -1
  106. data/lib/skynet/skynet_manager.rb +403 -240
  107. data/lib/skynet/skynet_message.rb +1 -3
  108. data/lib/skynet/skynet_message_queue.rb +42 -19
  109. data/lib/skynet/skynet_partitioners.rb +19 -15
  110. data/lib/skynet/skynet_ruby_extensions.rb +18 -0
  111. data/lib/skynet/skynet_tuplespace_server.rb +17 -14
  112. data/lib/skynet/skynet_worker.rb +132 -98
  113. data/lib/skynet/version.rb +1 -1
  114. data/script/destroy +0 -0
  115. data/script/generate +0 -0
  116. data/script/txt2html +0 -0
  117. data/test/test_helper.rb +2 -0
  118. data/test/test_skynet.rb +13 -5
  119. data/test/test_skynet_manager.rb +24 -9
  120. data/test/test_skynet_task.rb +1 -1
  121. data/website/index.html +77 -29
  122. data/website/index.txt +53 -24
  123. data/website/stylesheets/screen.css +12 -12
  124. metadata +156 -66
  125. data/app_generators/skynet_install/templates/skynet +0 -46
  126. data/log/skynet.log +0 -29
  127. data/log/skynet_tuplespace_server.log +0 -7
  128. data/log/skynet_worker.pid +0 -1
@@ -310,6 +310,7 @@ class Skynet
310
310
  end
311
311
 
312
312
  class WorkerStatusMessage < Skynet::Message
313
+ # I'd love to rename tasktype and tasksubtype to something more reasonable
313
314
  self.fields = [
314
315
  :tasktype,
315
316
  :tasksubtype,
@@ -330,13 +331,11 @@ class Skynet
330
331
 
331
332
  def initialize(opts)
332
333
  super
333
- self.tasktype = :status
334
334
  self.tasksubtype = :worker
335
335
  end
336
336
 
337
337
  def self.worker_status_template(opts)
338
338
  template = {
339
- :tasktype => :status,
340
339
  :tasksubtype => :worker,
341
340
  :hostname => opts[:hostname],
342
341
  :process_id => opts[:process_id]
@@ -348,7 +347,6 @@ class Skynet
348
347
 
349
348
  def self.all_workers_template(hostname=nil)
350
349
  template = {
351
- :tasktype => :status,
352
350
  :tasksubtype => :worker,
353
351
  :hostname => hostname,
354
352
  }
@@ -12,27 +12,48 @@ class Skynet
12
12
  class RequestExpiredError < Skynet::Error
13
13
  end
14
14
 
15
- # This class is the interface to the Skynet Message Queue.
15
+ # This class is the interface to the Skynet Message Queue.
16
16
  class MessageQueue
17
17
 
18
18
  include SkynetDebugger
19
19
 
20
- require 'forwardable'
21
- extend Forwardable
22
-
20
+ require 'forwardable'
21
+ extend Forwardable
22
+
23
23
  def self.adapter
24
- Object.module_eval(Skynet::CONFIG[:MESSAGE_QUEUE_ADAPTER], __FILE__, __LINE__).adapter
24
+ adapter_class.constantize.adapter
25
25
  end
26
26
 
27
- def initialize(message_queue_proxy_class=Skynet::CONFIG[:MESSAGE_QUEUE_ADAPTER])
28
- if message_queue_proxy_class.is_a?(String)
29
- @message_queue_proxy_class = Object.module_eval(message_queue_proxy_class, __FILE__, __LINE__)
30
- else
31
- @message_queue_proxy_class = message_queue_proxy_class
27
+ def self.adapter_class
28
+ Skynet::CONFIG[:MESSAGE_QUEUE_ADAPTER]
29
+ end
30
+
31
+ def self.start_or_connect(adapter_class = self.adapter_class)
32
+ begin
33
+ mq = new
34
+ rescue Skynet::ConnectionError
35
+ if self.adapter == :tuplespace
36
+ pid = fork do
37
+ exec("skynet_tuplespace_server start")
38
+ end
39
+ sleep 5
40
+ end
41
+ new
32
42
  end
43
+ end
44
+
45
+ def initialize(message_queue_proxy_class=Skynet::CONFIG[:MESSAGE_QUEUE_ADAPTER])
33
46
  mq
34
47
  end
35
48
 
49
+ def self.message_queue_proxy_class
50
+ adapter_class.constantize
51
+ end
52
+
53
+ def message_queue_proxy_class
54
+ @message_queue_proxy_class ||= self.class.message_queue_proxy_class
55
+ end
56
+
36
57
  # Is this version still active in the queue?
37
58
  def version_active?(version,queue_id=0)
38
59
  mq.version_active?(version,queue_id)
@@ -42,12 +63,12 @@ class Skynet
42
63
  def get_worker_version
43
64
  mq.get_worker_version
44
65
  end
45
-
66
+
46
67
  # Sets the current worker version (causing workers to restart)
47
68
  def set_worker_version(version)
48
69
  mq.set_worker_version(version)
49
70
  end
50
-
71
+
51
72
  # Increments the current worker version (causing workers to restart)
52
73
  def increment_worker_version
53
74
  newver = self.get_worker_version + 1
@@ -56,16 +77,18 @@ class Skynet
56
77
  end
57
78
 
58
79
  def mq
59
- @mq ||= @message_queue_proxy_class.new
80
+ @mq ||= message_queue_proxy_class.new(
81
+ :use_ringserver => Skynet::CONFIG[:TS_USE_RINGSERVER],
82
+ :ringserver_hosts => Skynet::CONFIG[:TS_SERVER_HOSTS],
83
+ :drburi => Skynet::CONFIG[:TS_DRBURI]
84
+ )
60
85
  end
61
-
86
+
62
87
  def_delegators :mq, :take_next_task, :write_message, :take_result, :write_error, :write_result,
63
- :list_tasks, :list_results, :stats,
64
- :clear_outstanding_tasks, :clear_outstanding_results,
65
- :take_worker_status, :write_worker_status, :read_all_worker_statuses, :clear_worker_status
66
-
88
+ :list_tasks, :list_results, :clear_outstanding_tasks, :clear_outstanding_results, :stats
89
+
90
+
67
91
 
68
-
69
92
  def message_fields
70
93
  Skynet::Message.fields
71
94
  end
@@ -51,14 +51,16 @@ class Skynet
51
51
  #
52
52
  def self.reduce_partition(post_map_data,new_partitions)
53
53
  return post_map_data unless post_map_data.is_a?(Array) and (not post_map_data.empty?) and post_map_data.first.is_a?(Array)
54
- if not post_map_data.first.first.is_a?(Array)
55
- partitioned_data = post_map_data.flatten
56
- else
54
+ ### Why did I do this? It breaks badly.
55
+ # if not post_map_data.first.first.is_a?(Array)
56
+ # partitioned_data = post_map_data.flatten
57
+ # else
57
58
  partitioned_data = post_map_data.inject(Array.new) do |data,part|
58
59
  data += part
59
60
  end
60
- end
61
+ # end
61
62
  partitioned_data = Skynet::Partitioners::SimplePartitionData.reduce_partition(partitioned_data, new_partitions)
63
+ debug "POST PARTITIONED DATA_SIZE", partitioned_data.size
62
64
  debug "POST PARTITIONED DATA", partitioned_data
63
65
  partitioned_data
64
66
  end
@@ -68,20 +70,22 @@ class Skynet
68
70
  # Smarter partitioner for array data, generates simple sum of array[0]
69
71
  # and ensures that all arrays sharing that key go into the same partition.
70
72
  #
71
- def self.reduce_partition(partitioned_data, new_partitions)
72
- partitions = Array.new
73
+ def self.reduce_partition(post_map_data, new_partitions)
74
+ partitions = []
73
75
  (0..new_partitions - 1).each { |i| partitions[i] = Array.new }
74
-
75
- partitioned_data.each do |partition|
76
- partition.each do |array|
77
- next unless array.class == Array and array.size == 2
76
+ cnt = 0
77
+ post_map_data.each do |partition|
78
+ partition.each do |array|
79
+ next unless array.is_a?(Array) and array.size >= 2
78
80
  if array[0].kind_of?(Fixnum)
79
- key = array[0]
80
- else
81
- key = 0
82
- array[0].each_byte { |c| key += c }
81
+ key = array[0] % new_partitions
82
+ elsif array[0].kind_of?(String)
83
+ key = array[0].sum % new_partitions
84
+ else
85
+ cnt += 1
86
+ key = cnt % new_partitions
83
87
  end
84
- partitions[key % new_partitions] << array
88
+ partitions[key] << array
85
89
  end
86
90
  end
87
91
  partitions
@@ -32,4 +32,22 @@ module Enumerable
32
32
  end
33
33
  job.run
34
34
  end
35
+ end
36
+
37
+ class String
38
+ ### THIS IS TAKEN DIRECTLY FROM ActiveSupport::Inflector
39
+ # Constantize tries to find a declared constant with the name specified
40
+ # in the string. It raises a NameError when the name is not in CamelCase
41
+ # or is not initialized.
42
+ #
43
+ # Examples
44
+ # "Module".constantize #=> Module
45
+ # "Class".constantize #=> Class
46
+ def constantize
47
+ unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ self
48
+ raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
49
+ end
50
+
51
+ Object.module_eval("::#{$1}", __FILE__, __LINE__)
52
+ end
35
53
  end
@@ -49,28 +49,31 @@ class Skynet
49
49
  class Job
50
50
  end
51
51
 
52
- class Server
52
+ class TuplespaceServer
53
53
 
54
- def initialize(options)
55
- log = Logger.new(options[:logfile], 'weekly')
56
- log.level = Object.module_eval("#{"Logger::" + options[:loglevel].upcase}", __FILE__, __LINE__)
57
- log.info "STARTING SKYNET SERVER ON PORT: #{options[:port]} Logging to #{options[:logfile]}"
54
+ def self.start(options)
55
+ options[:port] ||= 7647
56
+ log = Logger.new(options[:logfile])
57
+ log.level = Object.module_eval("#{"Logger::" + options[:loglevel].upcase}", __FILE__, __LINE__) if options[:loglevel]
58
+ log.info "STARTING TUPLESPACE SERVER ON PORT: #{options[:port]} Logging to #{options[:logfile]}"
58
59
 
59
60
  # Create a TupleSpace to hold named services, and start running
61
+ ts = Rinda::TupleSpace.new
60
62
  begin
61
- ts = Rinda::TupleSpace.new
63
+ if options[:use_ringserver] and options[:port]
64
+ DRb.start_service
65
+ tuple = [:name,:TupleSpace, ts, 'Tuple Space']
66
+ renewer = Rinda::SimpleRenewer.new
67
+ ring_ts = Rinda::TupleSpace.new
68
+ ring_ts.write(tuple, renewer)
69
+
70
+ server = Rinda::RingServer.new(ring_ts, options[:port])
71
+ end
62
72
  if options[:drburi]
63
73
  DRb.start_service(options[:drburi], ts)
64
- else
65
- DRb.start_service
66
74
  end
67
- tuple = [:name,:TupleSpace, ts, 'Tuple Space']
68
- renewer = Rinda::SimpleRenewer.new
69
- ring_ts = Rinda::TupleSpace.new
70
- ring_ts.write(tuple, renewer)
71
-
72
- server = Rinda::RingServer.new(ring_ts, options[:port])
73
75
  DRb.thread.join
76
+ rescue SystemExit, Interrupt
74
77
  rescue Exception, RuntimeError => e
75
78
  log.fatal "Couldn't start Skynet Server #{e.inspect}"
76
79
  end
@@ -1,7 +1,7 @@
1
- class Skynet
1
+ class Skynet
2
2
  class Worker
3
3
 
4
- include SkynetDebugger
4
+ include SkynetDebugger
5
5
  include Skynet::GuidGenerator
6
6
 
7
7
  RETRY_TIME = 2
@@ -14,7 +14,7 @@ class Skynet
14
14
 
15
15
  attr_accessor :message,:task, :mq, :processed
16
16
  attr_reader :worker_id, :worker_info, :worker_type, :queue_id
17
-
17
+
18
18
  class Error < StandardError; end
19
19
  class RespawnWorker < Skynet::Error; end
20
20
  class ConnectionFailure < Skynet::Error; end
@@ -23,57 +23,59 @@ class Skynet
23
23
  def self.debug_class_desc
24
24
  "WORKER-#{$$}"
25
25
  end
26
-
27
- def initialize(worker_type, options = {})
26
+
27
+ def initialize(worker_type, options = {})
28
28
  @worker_id = get_unique_id(1).to_i
29
29
  @worker_type = worker_type.to_sym
30
30
  @queue_id = options[:queue_id] || 0
31
31
  @processed = 0
32
+ @in_process = false
32
33
  @mq = Skynet::MessageQueue.new
33
34
 
34
35
  debug "THIS WORKER TAKES #{worker_type}"
35
36
 
36
- @worker_info = {
37
+ @worker_info = {
38
+ :tasktype => worker_type,
37
39
  :hostname => hostname,
38
40
  :process_id => process_id,
39
- :worker_type => payload_type,
41
+ :worker_type => payload_type,
40
42
  :worker_id => worker_id,
41
43
  :version => mq.get_worker_version,
42
- }
44
+ }
43
45
  @worker_info.merge!(options)
44
46
  end
45
47
 
46
48
  def process_id
47
49
  $$
48
50
  end
49
-
51
+
50
52
  def hostname
51
53
  @machine_name ||= Socket.gethostname
52
- end
53
-
54
+ end
55
+
54
56
  def version
55
57
  @curver
56
58
  end
57
-
59
+
58
60
  def new_version_respawn?
59
61
  if !@verchecktime
60
62
  @verchecktime = Time.now
61
- begin
63
+ begin
62
64
  @curver = mq.get_worker_version
63
65
  debug "FINDING INITIAL VER #{@curver}"
64
66
  rescue Skynet::RequestExpiredError => e
65
67
  warn "NO INITIAL VER IN MQ using 1"
66
68
  @curver = 1
67
69
  end
68
- else
70
+ else
69
71
  if Time.now < (@verchecktime + Skynet::CONFIG[:WORKER_VERSION_CHECK_DELAY])
70
72
  return false
71
- else
73
+ else
72
74
  @verchecktime = Time.now
73
75
  begin
74
76
  newver = mq.get_worker_version
75
77
  # debug "CURVER #{@curver} NEWVER: #{newver}"
76
- if newver != @curver and not mq.version_active?(@curver, queue_id)
78
+ if newver != @curver and not mq.version_active?(@curver, queue_id)
77
79
  info "RESTARTING WORKER ON PID #{$$}"
78
80
  return true
79
81
  end
@@ -85,19 +87,10 @@ class Skynet
85
87
  end
86
88
  end
87
89
  return false
88
- end
89
-
90
-
91
- def take_worker_status
92
- begin
93
- mq.take_worker_status(@worker_info,0.00001)
94
- rescue Skynet::RequestExpiredError, Skynet::QueueTimeout => e
95
- error "Couldnt take worker status for #{hostname} pid: #{process_id}"
96
- end
97
90
  end
98
-
91
+
99
92
  def notify_worker_started
100
- mq.write_worker_status(
93
+ write_worker_status(
101
94
  @worker_info.merge({
102
95
  :name => "waiting for #{@worker_type}",
103
96
  :processed => 0,
@@ -105,17 +98,19 @@ class Skynet
105
98
  })
106
99
  )
107
100
  end
108
-
101
+
109
102
  def notify_task_begun(task)
110
103
  task[:processed] = @processed
111
104
  task[:started_at] = Time.now.to_i
112
- mq.write_worker_status(@worker_info.merge(task))
105
+ @in_process = true
106
+ write_worker_status(@worker_info.merge(task))
113
107
  end
114
-
108
+
115
109
  def notify_task_complete
116
110
  @processed += 1
111
+ @in_process = false
117
112
 
118
- mq.write_worker_status(
113
+ write_worker_status(
119
114
  @worker_info.merge({
120
115
  :task_id => 0,
121
116
  :job_id => 0,
@@ -125,39 +120,74 @@ class Skynet
125
120
  :started_at => Time.now.to_i
126
121
  })
127
122
  )
128
- end
129
-
123
+ end
124
+
130
125
  def notify_worker_stop
131
126
  info "Worker #{process_id} stopping..."
132
- take_worker_status
133
- end
127
+ write_worker_status(
128
+ @worker_info.merge({
129
+ :task_id => 0,
130
+ :job_id => 0,
131
+ :name => "waiting for #{@worker_type}",
132
+ :processed => @processed,
133
+ :process_id => nil,
134
+ :map_or_reduce => nil,
135
+ :started_at => Time.now.to_i
136
+ })
137
+ )
138
+ end
139
+
140
+ def manager_send(method,*args)
141
+ begin
142
+ manager.send(method,*args)
143
+ rescue DRb::DRbConnError, Errno::ECONNREFUSED => e
144
+ error "Worker could not connect to manager to call #{method} on manager #{e.inspect}"
145
+ rescue Exception => e
146
+ error "Worker could not connect call #{method} on manager #{e.inspect} args:", args
147
+ end
148
+ end
149
+
150
+ def write_worker_status(status)
151
+ manager_send(:worker_notify,status)
152
+ end
153
+
154
+ def manager
155
+ Skynet::Manager.get
156
+ end
134
157
 
135
158
  def payload_type
136
159
  return nil if worker_type == :any
137
- return worker_type
160
+ return worker_type
138
161
  end
139
-
162
+
140
163
  def interrupt
141
164
  if @die
142
165
  exit
143
166
  else
144
167
  @die = true
145
- end
168
+ if not @in_process
169
+ notify_worker_stop
170
+ exit
171
+ end
172
+ end
146
173
  end
147
-
174
+
148
175
  def start
149
176
  exceptions = 0
150
177
  conerror = 0
151
178
  @curver = nil
152
-
179
+
153
180
  # setup signal handlers for manager
154
- Signal.trap("HUP") { @respawn = true }
181
+ Signal.trap("HUP") do
182
+ @respawn = true
183
+ raise Skynet::Worker::RespawnWorker.new if not @in_process
184
+ end
155
185
  Signal.trap("TERM") { interrupt }
156
- Signal.trap("INT") { @die = true }
157
-
186
+ Signal.trap("INT") { interrupt }
187
+
158
188
  raise Skynet::Worker::RespawnWorker.new if new_version_respawn?
159
-
160
- info "STARTING WORKER @ VER #{@curver} (#{@worker_type}) QUEUE_ID: #{queue_id}"
189
+
190
+ printlog "STARTING WORKER @ VER:#{@curver} type:#{@worker_type} QUEUE_ID:#{queue_id}"
161
191
 
162
192
  notify_worker_started
163
193
 
@@ -165,13 +195,13 @@ class Skynet
165
195
  task = nil
166
196
 
167
197
  loop do
168
- message = nil
169
- begin
198
+ message = nil
199
+ begin
170
200
  if Skynet::CONFIG[:WORKER_MAX_PROCESSED] and Skynet::CONFIG[:WORKER_MAX_PROCESSED] > 0 and @processed >= Skynet::CONFIG[:WORKER_MAX_PROCESSED]
171
201
  raise Skynet::Worker::RespawnWorker.new("WORKER OVER MAX MEM AT: #{get_memory_size} MAX: #{Skynet::CONFIG[:WORKER_MAX_MEMORY]}")
172
202
  end
173
- if @die
174
- exit
203
+ if @die
204
+ exit
175
205
  elsif @respawn
176
206
  raise Skynet::Worker::RespawnWorker.new()
177
207
  end
@@ -179,7 +209,7 @@ class Skynet
179
209
  if local_mem = max_memory_reached?
180
210
  raise Skynet::Worker::RespawnWorker.new("WORKER OVER MAX MEM AT: #{local_mem} MAX: #{Skynet::CONFIG[:WORKER_MAX_MEMORY]}")
181
211
  end
182
-
212
+
183
213
  if conerror > 0
184
214
  @mq = Skynet::MessageQueue.new
185
215
  warn "WORKER RECONNECTED AFTER #{conerror} tries"
@@ -187,14 +217,14 @@ class Skynet
187
217
  end
188
218
 
189
219
  # debug "1 START LOOPSSS at VER #{@curver}"
190
- #
220
+ #
191
221
  # debug "LOOK FOR WORK USING TEMPLATE", Skynet::Message.task_template(@curver)
192
222
  # message = Skynet::Message.new(mq.take(Skynet::Message.task_template(@curver),0.00001))
193
223
  message = mq.take_next_task(@curver, 0.00001, payload_type, queue_id)
194
224
 
195
225
  next unless message.respond_to?(:payload)
196
226
 
197
- task = message.payload
227
+ task = message.payload
198
228
  error "BAD MESSAGE", task unless task.respond_to?(:map_or_reduce)
199
229
 
200
230
  info "STEP 2 GOT MESSAGE #{message.name} type:#{task.map_or_reduce}, jobid: #{message.job_id}, taskid:#{message.task_id} it: #{message.iteration}"
@@ -207,11 +237,11 @@ class Skynet
207
237
  # task.debug "taking task #{task.task_id} name:#{task.name}..."
208
238
 
209
239
  info "STEP 4 RUNNING TASK #{message.name} jobid: #{message.job_id} taskid: #{task.task_id}"
210
- notify_task_begun({
211
- :job_id => message.job_id,
212
- :task_id => message.task_id,
213
- :iteration => message.iteration,
214
- :name => message.name,
240
+ notify_task_begun({
241
+ :job_id => message.job_id,
242
+ :task_id => message.task_id,
243
+ :iteration => message.iteration,
244
+ :name => message.name,
215
245
  :map_or_reduce => task.map_or_reduce
216
246
  })
217
247
  result = task.run(message.iteration)
@@ -222,22 +252,22 @@ class Skynet
222
252
  result_message = mq.write_result(message,result,task.result_timeout)
223
253
  info "STEP 6 WROTE RESULT MESSAGE #{message.name} jobid: #{message.job_id} taskid: #{task.task_id}"
224
254
  # debug "STEP 6.1 RESULT_MESSAGE:", result_message
225
- notify_task_complete
255
+ notify_task_complete
226
256
 
227
257
  rescue Skynet::Task::TimeoutError => e
228
258
  error "Task timed out while executing #{e.inspect} #{e.backtrace.join("\n")}"
259
+ @in_process = false
229
260
  next
230
261
 
231
- rescue Skynet::Worker::RespawnWorker => e
262
+ rescue Skynet::Worker::RespawnWorker => e
232
263
  info "Respawning and taking worker status #{e.message}"
233
264
  notify_worker_stop
234
- raise e
265
+ raise e
235
266
 
236
267
  rescue Skynet::RequestExpiredError => e
237
268
  if new_version_respawn?
238
269
  notify_worker_stop
239
- manager = DRbObject.new(nil, Skynet::CONFIG[:SKYNET_LOCAL_MANAGER_URL])
240
- manager.restart_worker($$) if manager
270
+ manager_send(:restart_worker,$$)
241
271
  end
242
272
  sleep 1
243
273
  next
@@ -251,15 +281,15 @@ class Skynet
251
281
  if conerror > 20
252
282
  fatal "TOO MANY RECONNECTION EXCEPTIONS #{e.message}"
253
283
  notify_worker_stop
254
- raise e
284
+ raise e
255
285
  end
256
286
  next
257
287
 
258
288
  rescue NoManagerError => e
259
289
  fatal e.message
260
- break
290
+ break
261
291
  rescue Interrupt, SystemExit => e
262
- warn "Exiting..."
292
+ info "Exiting..."
263
293
  notify_worker_stop
264
294
  break
265
295
  rescue Exception => e
@@ -274,6 +304,7 @@ class Skynet
274
304
  # mq.write_error(message,"ERROR in WORKER [#{$$}] #{e.inspect} #{e.backtrace.join("\n")}")
275
305
  end
276
306
  # mq.write_error("ERROR in WORKER [#{$$}] #{e.inspect} #{e.backtrace.join("\n")}")
307
+ @in_process = false
277
308
  next
278
309
  end
279
310
  end
@@ -282,7 +313,7 @@ class Skynet
282
313
  @@ok_to_mem_check = false
283
314
  @@lastmem = nil
284
315
  @@memct = 0
285
-
316
+
286
317
  def max_memory_reached?
287
318
  return false unless ok_to_mem_check?
288
319
  if !@memchecktime
@@ -296,7 +327,7 @@ class Skynet
296
327
  false
297
328
  end
298
329
  end
299
-
330
+
300
331
  def find_pid_size(file, format=:notpretty)
301
332
  begin
302
333
  open(file).each { |line|
@@ -321,49 +352,38 @@ class Skynet
321
352
  return false if @@ok_to_mem_check == :notok
322
353
  if File.exists?('/proc/self/status')
323
354
  @@lastmem ||= get_memory_size.to_i
324
- return @@ok_to_mem_check = true
355
+ return @@ok_to_mem_check = true
325
356
  else
326
357
  @@ok_to_mem_check = :notok
327
- return false
328
- end
329
- end
330
-
331
-
332
- # kinda like system() but gives me back a pid
333
- def self.fork_and_exec(command)
334
- sleep 0.01 # remove contention on manager drb object
335
- log = Skynet::Logger.get
336
- info "executing /bin/sh -c \"#{command}\""
337
- pid = fork do
338
- exec("/bin/sh -c \"#{command}\"")
339
- exit
358
+ return false
340
359
  end
341
- Process.detach(pid)
342
- pid
343
360
  end
344
361
 
345
362
  def self.start(options={})
346
363
  options[:worker_type] ||= :any
347
364
  options[:required_libs] ||= []
348
-
365
+
349
366
  OptionParser.new do |opt|
350
367
  opt.banner = "Usage: worker [options]"
351
368
  opt.on('-r', '--required LIBRARY', 'Include the specified libraries') do |v|
352
369
  options[:required_libs] << v
353
370
  end
354
- opt.on('-ot', '--worker_type WORKERTYPE', "master, task or any") do |v|
371
+ opt.on('--worker_type=WORKERTYPE', "master, task or any") do |v|
355
372
  if ["any","master","task"].include?(v)
356
373
  options[:worker_type] = v
357
374
  else
358
375
  raise Skynet::Error.new("#{v} is not a valid worker_type")
359
376
  end
360
377
  end
361
- opt.on('-q', '--queue QUEUE_NAME', 'Which queue should these workers use (default "default").') do |v|
378
+ opt.on('--config=CONFIG_FILE', 'Where to find the skynet.rb config file') do |v|
379
+ options[:config_file] = File.expand_path(v)
380
+ end
381
+ opt.on('--queue=QUEUE_NAME', 'Which queue should these workers use (default "default").') do |v|
362
382
  options[:queue] = v
363
- end
364
- opt.on('-i', '--queue_id queue_id', 'Which queue should these workers use (default 0).') do |v|
383
+ end
384
+ opt.on('--queue_id=queue_id', 'Which queue should these workers use (default 0).') do |v|
365
385
  options[:queue_id] = v.to_i
366
- end
386
+ end
367
387
  opt.parse!(ARGV)
368
388
  end
369
389
 
@@ -381,21 +401,35 @@ class Skynet
381
401
  error "The included lib #{adlib} was not found: #{e.inspect}"
382
402
  exit
383
403
  end
384
- end
404
+ end
405
+
406
+ options[:config_file] ||= Skynet::CONFIG[:CONFIG_FILE]
407
+ if options[:config_file]
408
+ begin
409
+ require options[:config_file]
410
+ rescue MissingSourceFile => e
411
+ error "The config file at #{options[:config_file]} was not found: #{e.inspect}"
412
+ exit
413
+ end
414
+ else
415
+ error "Config file missing. Please add a config/skynet_config.rb before starting."
416
+ exit
417
+ end
385
418
 
386
419
  debug "WORKER STARTING WORKER_TYPE?:#{options[:worker_type]}. QUEUE: #{Skynet::Config.new.queue_name_by_id(options[:queue_id])}"
387
420
 
388
- begin
421
+ begin
389
422
  worker = Skynet::Worker.new(options[:worker_type], options)
390
423
  worker.start
391
424
  rescue Skynet::Worker::NoManagerError => e
392
425
  fatal e.message
393
- exit
426
+ exit
394
427
  rescue Skynet::Worker::RespawnWorker => e
395
428
  warn "WORKER #{$$} SCRIPT CAUGHT RESPAWN. RESTARTING #{e.message}"
396
- cmd = "ruby #{Skynet::CONFIG[:LAUNCHER_PATH]} --worker_type=#{options[:worker_type]} --queue_id=#{options[:queue_id]}"
429
+ cmd = "ruby #{Skynet::CONFIG[:LAUNCHER_PATH]} --worker_type=#{options[:worker_type]} --queue_id=#{options[:queue_id]} "
430
+ cmd << "--config=#{options[:config_file]} "
397
431
  cmd << "-r #{options[:required_libs].join(' -r ')}" if options[:required_libs] and not options[:required_libs].empty?
398
- pid = fork_and_exec(cmd)
432
+ pid = Skynet.fork_and_exec(cmd)
399
433
  exit
400
434
  rescue SystemExit
401
435
  info "WORKER #{$$} EXITING GRACEFULLY"
@@ -408,10 +442,10 @@ class Skynet
408
442
  end
409
443
  end
410
444
 
411
- class ExceptionReport
412
- def initialize(*args)
413
- end
414
-
445
+ class ExceptionReport
446
+ def initialize(*args)
447
+ end
448
+
415
449
  def save
416
450
  end
417
451
  end