refinery 0.12.2 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/lib/refinery.rb +1 -99
  2. data/refinery.gemspec +16 -117
  3. metadata +39 -118
  4. data/.gitignore +0 -6
  5. data/CHANGELOG +0 -2
  6. data/LICENSE +0 -21
  7. data/README.rdoc +0 -58
  8. data/README.textile +0 -58
  9. data/Rakefile +0 -43
  10. data/VERSION +0 -1
  11. data/bin/epub +0 -64
  12. data/bin/monitor +0 -47
  13. data/bin/pubnow +0 -61
  14. data/bin/refinery +0 -64
  15. data/config/config.example.yml +0 -21
  16. data/lib/refinery/beanstalk_queue.rb +0 -36
  17. data/lib/refinery/beanstalk_queue_provider.rb +0 -18
  18. data/lib/refinery/config.rb +0 -48
  19. data/lib/refinery/configurable.rb +0 -15
  20. data/lib/refinery/daemon.rb +0 -148
  21. data/lib/refinery/event_publisher.rb +0 -131
  22. data/lib/refinery/heartbeat.rb +0 -33
  23. data/lib/refinery/loggable.rb +0 -9
  24. data/lib/refinery/monitor.rb +0 -113
  25. data/lib/refinery/processor.rb +0 -55
  26. data/lib/refinery/publisher.rb +0 -42
  27. data/lib/refinery/queueable.rb +0 -48
  28. data/lib/refinery/server.rb +0 -88
  29. data/lib/refinery/statistics.rb +0 -61
  30. data/lib/refinery/stats_server.rb +0 -135
  31. data/lib/refinery/utilities.rb +0 -33
  32. data/lib/refinery/validations.rb +0 -48
  33. data/lib/refinery/worker.rb +0 -65
  34. data/logs/README +0 -1
  35. data/publishers/error.rb +0 -6
  36. data/publishers/sample.rb +0 -6
  37. data/publishers/sleep.rb +0 -5
  38. data/test/config.yml +0 -10
  39. data/test/test_helper.rb +0 -21
  40. data/test/unit/config_test.rb +0 -42
  41. data/test/unit/configurable_test.rb +0 -13
  42. data/test/unit/daemon_test.rb +0 -63
  43. data/test/unit/event_publisher_test.rb +0 -12
  44. data/test/unit/heartbeat_test.rb +0 -25
  45. data/test/unit/loggable_test.rb +0 -12
  46. data/test/unit/processor_test.rb +0 -34
  47. data/test/unit/publisher_test.rb +0 -13
  48. data/test/unit/queueable_test.rb +0 -26
  49. data/test/unit/server_test.rb +0 -34
  50. data/test/unit/statistics_test.rb +0 -44
  51. data/test/unit/utilities_test.rb +0 -25
  52. data/test/unit/validations_test.rb +0 -37
  53. data/test/unit/worker_test.rb +0 -44
  54. data/workers/error.rb +0 -8
  55. data/workers/sample.rb +0 -8
  56. data/workers/sleep.rb +0 -7
@@ -1,55 +0,0 @@
1
- module Refinery #:nodoc:
2
- # This class is used to monitor all of the threads for a single
3
- # processor.
4
- class Processor < Thread
5
- include Refinery::Configurable
6
- include Refinery::Loggable
7
-
8
- attr_reader :server
9
- attr_reader :key
10
- attr_reader :settings
11
- attr_reader :daemons
12
-
13
- # Initialize the processor.
14
- def initialize(server, key, settings={})
15
- @server = server
16
- @key = key
17
- @settings = settings
18
- @daemons = []
19
- super do
20
- execute
21
- end
22
- end
23
-
24
- private
25
- # Execute the processor
26
- def execute
27
- queue_prefix = config['prefix'] || ''
28
-
29
- if defined?(java.lang.Thread)
30
- java.lang.Thread.current_thread.name = "#{key} Processor"
31
- end
32
-
33
- logger.debug "Creating daemons for #{key}"
34
- 1.upto(settings['workers']['initial']) do
35
- daemons << Daemon.new(self, key, queue_prefix, settings)
36
- end
37
-
38
- logger.debug "Running #{daemons.length} daemons"
39
-
40
- wait = ThreadsWait.new(*daemons)
41
- wait.all_waits do |daemon|
42
- logger.debug "a #{daemon.name} just died"
43
- daemons.delete(daemon)
44
- logger.debug "waiting for 60 seconds before starting a new #{key} daemon"
45
- sleep(60)
46
- logger.debug "starting a new #{key} daemon"
47
- daemon = Daemon.new(self, key, queue_prefix, settings)
48
- daemons << daemon
49
- wait.join(daemon)
50
- end
51
-
52
- logger.debug "Processor #{key} is exiting"
53
- end
54
- end
55
- end
@@ -1,42 +0,0 @@
1
- module Refinery #:nodoc:
2
- # Base class for publishers to be implemented by subclasses.
3
- class Publisher
4
- include Refinery::Loggable
5
- include Refinery::Queueable
6
-
7
- # Initialize the publisher with the queue to publish messages to.
8
- def initialize(waiting_queue_name)
9
- @waiting_queue_name = waiting_queue_name
10
- end
11
-
12
- protected
13
- # Get the publish queue name
14
- def waiting_queue_name
15
- @waiting_queue_name
16
- end
17
-
18
- # Publish the message. The message will be converted to JSON and pushed
19
- # into the queue associated with the publisher.
20
- def publish(message)
21
- with_queue(waiting_queue_name) do |waiting_queue|
22
- publish_to_queue(waiting_queue, message)
23
- end
24
- end
25
-
26
- # Publish the given message if the waiting queue is empty. The message will
27
- # be converted to JSON and pushed into the queue associated with the
28
- # publisher.
29
- def publish_if_empty(message)
30
- with_queue(waiting_queue_name) do |waiting_queue|
31
- publish_to_queue(waiting_queue, message) if waiting_queue.size == 0
32
- end
33
- end
34
-
35
- # Publish the given message to the queue. The message will be converted
36
- # to JSON and pushed into the queue associated with the publisher.
37
- def publish_to_queue(queue, message)
38
- logger.debug "Publisher #{self.class.name} sending message: #{message.to_json}"
39
- queue.send_message(Base64.encode64(message.to_json))
40
- end
41
- end
42
- end
@@ -1,48 +0,0 @@
1
- module Refinery #:nodoc:
2
- # Mix this module in to classes that want to access a queue.
3
- module Queueable
4
- include Loggable
5
- include Configurable
6
- # Get a named queue
7
- def queue(name)
8
- queue_provider.queue(name)
9
- end
10
-
11
- # Given the queue name and a block, yield the named queue into
12
- # the block.
13
- def with_queue(name, &block)
14
- begin
15
- yield queue(name)
16
- rescue Exception => e
17
- logger.error "An error occurred when communicating with queue #{name}: #{e.message}"
18
- sleep(30)
19
- end
20
- end
21
-
22
- protected
23
- # Get the queue provider. Defaults to RightAws::SqsGen2 running
24
- # in multi-thread mode.
25
- def queue_provider
26
- if queue_engine = config['queue_engine']
27
- if queue_engine['provider'] == 'beanstalk' && defined?(Beanstalk)
28
- @queue_provider ||= Refinery::BeanstalkQueueProvider.new
29
- else
30
- raise RuntimeError, "Unknown queue provider: #{queue_engine['provider']}"
31
- end
32
- else
33
- if defined?(Typica)
34
- @queue_provider ||= Typica::Sqs::QueueService.new(
35
- config['aws']['credentials']["access_key_id"],
36
- config['aws']['credentials']["secret_access_key"]
37
- )
38
- else
39
- @queue_provider ||= RightAws::SqsGen2.new(
40
- config['aws']['credentials']["access_key_id"],
41
- config['aws']['credentials']["secret_access_key"],
42
- {:multi_thread => true}
43
- )
44
- end
45
- end
46
- end
47
- end
48
- end
@@ -1,88 +0,0 @@
1
- module Refinery #:nodoc:
2
- # The server instance provides a runtime environment for daemons.
3
- # To start the server create an Refinery::Server instance and invoke run.
4
- class Server
5
- include Refinery::Loggable
6
- include Refinery::Configurable
7
- include Refinery::Queueable
8
- include Refinery::Utilities
9
-
10
- # The directory where worker source files are stored. Defaults to
11
- # ./workers
12
- attr_accessor :workers_directory
13
-
14
- # Get a server-wide logger
15
- def self.logger
16
- @logger ||= begin
17
- logger = Logger.new(STDOUT)
18
- logger.level = Logger::WARN
19
- logger.formatter = CustomFormatter.new
20
- logger
21
- end
22
- end
23
-
24
- # Initialize the server.
25
- #
26
- # Options:
27
- # * <tt>:config</tt>: Provide a file path to load that config
28
- # * <tt>:debug</tt>: Set to true to enable debug logging
29
- # * <tt>:verbose</tt>: Set to true to enable info logging
30
- # * <tt>:workers</tt>: The workers directory
31
- def initialize(options={})
32
- logger.level = Logger::INFO if options[:verbose]
33
- logger.level = Logger::DEBUG if options[:debug]
34
- config.load_file(options[:config]) if options[:config]
35
- self.workers_directory = options[:workers] if options[:workers]
36
- end
37
-
38
- # The directory where workers are found. Defaults to ./workers
39
- def workers_directory
40
- @workers_directory ||= "./workers"
41
- end
42
-
43
- # Stop the server
44
- def stop
45
- logger.info "Stopping Refinery Server"
46
- daemons.each { |daemon| daemon.stop }
47
- end
48
-
49
- # An array of all daemons
50
- def daemons
51
- @daemons ||= []
52
- end
53
-
54
- # Run the server
55
- def run
56
- logger.info "Starting Refinery server"
57
- execute_processors
58
- logger.info "Server is exiting"
59
- end
60
-
61
- private
62
- def execute_processors
63
-
64
- @processors = config['processors'].map do |key, settings|
65
- Processor.new(self, key, settings)
66
- end
67
-
68
- Heartbeat.new(self)
69
-
70
- begin
71
- @processors.each { |p| p.join }
72
- rescue Interrupt => e
73
- end
74
- end
75
- end
76
-
77
- class CustomFormatter
78
- def format
79
- @format ||= "%s, [%s#%d][%s] %5s -- %s: %s\n"
80
- end
81
- def call(severity, time, progname, msg)
82
- format % [severity[0..0], format_datetime(time.utc), $$, Thread.current.object_id.to_s, severity, progname, msg.to_s]
83
- end
84
- def format_datetime(time)
85
- time.strftime("%Y-%m-%dT%H:%M:%S.") << "%06d " % time.usec
86
- end
87
- end
88
- end
@@ -1,61 +0,0 @@
1
- module Refinery #:nodoc:
2
- # The statistics class provides a means to record runtime stats
3
- # about completed jobs and errors. The stats are stored in a SQL
4
- # database (using SQLite3 by default).
5
- class Statistics
6
- include Refinery::Loggable
7
-
8
- # Record the done record into the
9
- def record_done(message)
10
- db[:completed_jobs] << {
11
- :host => message['host_info']['hostname'],
12
- :pid => message['host_info']['pid'],
13
- :run_time => message['run_time'],
14
- :original_message => message['original'],
15
- :when => Time.now
16
- }
17
- end
18
-
19
- # Record the error message into the statistics database.
20
- def record_error(message)
21
- db[:errors] << {
22
- :host => message['host_info']['hostname'],
23
- :pid => message['host_info']['pid'],
24
- :error_class => message['error']['class'],
25
- :error_message => message['error']['message'],
26
- :original_message => message['original'],
27
- :when => Time.now
28
- }
29
- end
30
-
31
- private
32
- # Get a Sequel connection to the stats database
33
- def db
34
- @db ||= begin
35
- db = Sequel.connect('sqlite://stats.db')
36
- unless db.table_exists?(:completed_jobs)
37
- db.create_table :completed_jobs do
38
- primary_key :id
39
- column :host, :text
40
- column :pid, :integer
41
- column :run_time, :float
42
- column :original_message, :text
43
- column :when, :time
44
- end
45
- end
46
- unless db.table_exists?(:errors)
47
- db.create_table :errors do
48
- primary_key :id
49
- column :host, :text
50
- column :pid, :integer
51
- column :error_class, :text
52
- column :error_message, :text
53
- column :original_message, :text
54
- column :when, :time
55
- end
56
- end
57
- db
58
- end
59
- end
60
- end
61
- end
@@ -1,135 +0,0 @@
1
- module Refinery #:nodoc:
2
- # The StatsServer class provides a build in web server that provides
3
- # a view into the refinery statistics. This functionality is very
4
- # experimental.
5
- class StatsServer
6
- include Refinery::Loggable
7
-
8
- # Run the stats server.
9
- def run
10
- begin
11
- Ramaze::Log.loggers.clear # supress all Ramaze logging
12
- Ramaze.start # start the Ramaze server on port 7000
13
- rescue NameError
14
- self.logger.warn "Install Ramaze to enable the stats server"
15
- end
16
- end
17
-
18
- if const_defined?(:Ramaze)
19
- class MainController < ::Ramaze::Controller #:nodoc:
20
- map '/'
21
-
22
- def index
23
- %(
24
- <html>
25
- <head>
26
- <title>Refinery Stats</title>
27
- <style>
28
- .widget { border: 1px solid #777; margin-bottom: 10px; padding: 4px; }
29
- .widget h2 { font-size: 14pt; margin-top: 2px; margin-bottom: 2px; }
30
- #left-column { float: left; width: 600px; }
31
- #right-column { margin-left: 610px; width: 300px; }
32
- table { background-color: #ddd; width: 100%; }
33
- table td { background-color: #eee; }
34
- table th { background-color: #ccc; }
35
- </style>
36
- </head>
37
- <body>
38
- <h1>Refinery Stats</h1>
39
- <div id="left-column">
40
- <div class="run_time widget">
41
- <h2>Runtime Averages</h2>
42
- #{avg_run_time}
43
- </div>
44
- <div class="errors widget">
45
- <h2>Last 5 Errors</h2>
46
- #{errors_table}
47
- </div>
48
- <div class="completed widget">
49
- <h2>Last 5 Completed Jobs</h2>
50
- #{completed_jobs_table}
51
- </div>
52
- </div>
53
- <div id="right-column">
54
- <div class="overview widget">
55
- <h2>Overview</h2>
56
- <div>#{db[:completed_jobs].count} jobs completed</div>
57
- <div>#{db[:errors].count} errors</div>
58
- </div>
59
-
60
- </div>
61
- </body>
62
- </html>
63
- )
64
- end
65
-
66
- private
67
- def db
68
- Sequel.connect("sqlite://stats.db")
69
- end
70
-
71
- def avg_run_time
72
- rows = db[:completed_jobs].group(:host, :pid).select(:host, :pid, :AVG.sql_function(:run_time)).map do |record|
73
- %(<tr>
74
- <td>#{record[:host]}</td>
75
- <td>#{record[:pid]}</td>
76
- <td>#{sprintf("%.6f", record[:"AVG(`run_time`)"])}</td>
77
- </tr>)
78
- end.join
79
- %(
80
- <table>
81
- <tr>
82
- <th>Host</th>
83
- <th>PID</th>
84
- <th>Avg Run Time</th>
85
- </tr>
86
- #{rows}
87
- </table>
88
- )
89
- end
90
-
91
- def completed_jobs_table
92
- jobs_list = db[:completed_jobs].limit(5).map do |record|
93
- %Q( <tr>
94
- <td>#{record[:host]}</td>
95
- <td>#{record[:pid]}</td>
96
- <td>#{record[:run_time]}</td>
97
- </tr>
98
- )
99
- end
100
- %Q( <table>
101
- <tr>
102
- <th>Host</th>
103
- <th>PID</th>
104
- <th>Run Time</th>
105
- </tr>
106
- #{jobs_list.join}
107
- </table>
108
- )
109
- end
110
-
111
- def errors_table
112
- errors = db[:errors].limit(5).map do |record|
113
- %(<tr>
114
- <td>#{record[:host]}</td>
115
- <td>#{record[:pid]}</td>
116
- <td>#{record[:error_class]}</td>
117
- <td>#{record[:error_message]}</td>
118
- </tr>
119
- )
120
- end
121
- %(<table>
122
- <tr>
123
- <th>Host</th>
124
- <th>PID</th>
125
- <th>Error Class</th>
126
- <th>Error Message</th>
127
- </tr>
128
- #{errors.join}
129
- </table>
130
- )
131
- end
132
- end
133
- end
134
- end
135
- end
@@ -1,33 +0,0 @@
1
- module Refinery #:nodoc:
2
- # Utilities that can be mixed into a class
3
- module Utilities
4
- # Camelize the given word.
5
- def camelize(word, first_letter_in_uppercase = true)
6
- if first_letter_in_uppercase
7
- word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
8
- else
9
- word.first.downcase + camelize(word)[1..-1]
10
- end
11
- end
12
-
13
- # Decode the message_body from Base 64 and then parse from JSON.
14
- def decode_message(message_body)
15
- JSON.parse(Base64.decode64(message_body))
16
- end
17
-
18
- # Convert the given message_data object to JSON and then Base 64
19
- # encode it
20
- def encode_message(message_data)
21
- Base64.encode64(message_data.to_json)
22
- end
23
-
24
- # Get a Hash of useful host information that can be sent with
25
- # messages to the monitoring system.
26
- def host_info
27
- {
28
- 'hostname' => Socket.gethostname,
29
- 'pid' => $$
30
- }
31
- end
32
- end
33
- end