refinery 0.12.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.
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