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,18 +0,0 @@
1
- module Refinery #:nodoc:
2
- # A queue provider for beanstalk
3
- class BeanstalkQueueProvider
4
- include Refinery::Loggable
5
-
6
- attr_reader :queues
7
-
8
- # Initialize the queue provider
9
- def initialize(hosts=nil)
10
- @hosts = hosts
11
- @queues = {}
12
- end
13
- # Get the named queue
14
- def queue(name)
15
- queues[name] ||= Refinery::BeanstalkQueue.new(name, @hosts)
16
- end
17
- end
18
- end
@@ -1,48 +0,0 @@
1
- module Refinery #:nodoc:
2
- # Configuration class.
3
- class Config
4
- # Get a shared configuration
5
- def self.default
6
- @default ||= new({
7
- 'aws' => {
8
- 'credentials' => {}
9
- },
10
- 'processors' => {}
11
- })
12
- end
13
-
14
- # Initialize the config with the given data
15
- def initialize(data={})
16
- @data = data
17
- end
18
-
19
- # Get the configuration value
20
- def [](key)
21
- data[key.to_s]
22
- end
23
-
24
- # Set the configuration value
25
- def []=(key, value)
26
- data[key.to_s] = value
27
- end
28
-
29
- # Load configuration from a YAML file
30
- def load_file(file)
31
- @file = file
32
- @data = YAML::load_file(@file)
33
- @last_load = File.mtime(@file)
34
- end
35
-
36
- # Refresh the configuration from the YAML file if necessary.
37
- def refresh
38
- if File.mtime(@file) != @last_load
39
- @data = YAML::load_file(@file)
40
- end
41
- end
42
-
43
- private
44
- def data
45
- @data ||= {}
46
- end
47
- end
48
- end
@@ -1,15 +0,0 @@
1
- module Refinery #:nodoc:
2
- # Include this module to get access to a shared configuration
3
- module Configurable
4
- # Get the configuration. If the config is nil then this will use
5
- # the default shared configuration.
6
- def config
7
- @config ||= Refinery::Config.default
8
- end
9
-
10
- # Set the configuration.
11
- def config=(config)
12
- @config = config
13
- end
14
- end
15
- end
@@ -1,148 +0,0 @@
1
- module Refinery #:nodoc:
2
- # A daemon provides a thread to run workers in.
3
- class Daemon < Thread
4
- include Refinery::Loggable
5
- include Refinery::Configurable
6
- include Refinery::Utilities
7
- include Refinery::Queueable
8
-
9
- RUNNING = 'running'
10
- STOPPED = 'stopped'
11
-
12
- # The name of the daemon
13
- attr_reader :name
14
- # The settings for the daemon
15
- attr_reader :settings
16
- # The base queue name
17
- attr_reader :queue_name
18
-
19
- # Stop the daemon
20
- def stop
21
- self.state = STOPPED
22
- end
23
-
24
- # Return the daemon state
25
- def state
26
- @state ||= RUNNING
27
- end
28
-
29
- # Set the daemon state.
30
- def state=(state)
31
- @state = state
32
- end
33
- protected :state
34
-
35
- # Return true if the daemon state is running.
36
- def running?
37
- state == RUNNING
38
- end
39
-
40
- # Initialize the daemon.
41
- #
42
- # * <tt>processor</tt>: The processor instance
43
- # * <tt>name</tt>: The processor name
44
- # * <tt>waiting_queue</tt>: The waiting queue that provides messages to be processed
45
- # * <tt>error_queue</tt>: The queue where errors are posted.
46
- # * <tt>done_queue</tt>: The queue for messages that have been processed.
47
- # * <tt>settings</tt>: The settings hash from the config.
48
- #
49
- # The settings hash may contain the following options:
50
- # * <tt>visibility</tt>: The time in seconds that the message is hidden
51
- # in the queue.
52
- def initialize(processor, name, queue_prefix='', settings={})
53
- logger.debug "Starting daemon"
54
-
55
- @processor = processor
56
- @name = name
57
- @settings = settings
58
-
59
- queue_name = settings['queue'] || name
60
- queue_name = "#{queue_prefix}#{queue_name}"
61
- logger.debug "Using queue #{queue_name}"
62
- @queue_name = queue_name
63
-
64
- super do
65
- begin
66
- execute
67
- rescue Exception => e
68
- logger.error e
69
- end
70
- end
71
- end
72
-
73
- private
74
- def execute
75
- logger.debug "Running daemon thread: #{name} (settings: #{settings.inspect})"
76
-
77
- if defined?(java.lang.Thread)
78
- java.lang.Thread.current_thread.name = "#{name} Daemon"
79
- end
80
-
81
- while(running?)
82
- #logger.debug "Checking #{queue_name}_waiting"
83
- with_queue("#{queue_name}_waiting") do |waiting_queue|
84
- while (message = waiting_queue.receive(settings['visibility']))
85
- worker = load_worker_class(name).new(self)
86
- begin
87
- result, run_time = worker.run(decode_message(message.body))
88
- if result
89
- with_queue("#{queue_name}_done") do |done_queue|
90
- done_message = {
91
- 'host_info' => host_info,
92
- 'original' => message.body,
93
- 'run_time' => run_time
94
- }
95
- logger.debug "Sending 'done' message to #{done_queue.name}"
96
- done_queue.send_message(encode_message(done_message))
97
- end
98
-
99
- logger.debug "Deleting message from queue"
100
- message.delete()
101
- end
102
- rescue Exception => e
103
- with_queue("#{queue_name}_error") do |error_queue|
104
- error_message = {
105
- 'error' => {
106
- 'message' => e.message,
107
- 'class' => e.class.name,
108
- 'backtrace' => e.backtrace
109
- },
110
- 'host_info' => host_info,
111
- 'original' => message.body
112
- }
113
- logger.error "Sending 'error' message to #{error_queue.name}: #{e.message}"
114
- error_queue.send_message(encode_message(error_message))
115
- end
116
- message.delete()
117
- end
118
- end
119
- sleep(settings['sleep'] || 5)
120
- end
121
- end
122
- logger.debug "Exiting daemon thread"
123
- end
124
-
125
- # A hash of worker classes
126
- def workers
127
- @workers ||= {}
128
- end
129
-
130
- private
131
- # Load the appropriate worker class
132
- def load_worker_class(name)
133
- source_file = "#{@processor.server.workers_directory}/#{name}.rb"
134
- if File.exist?(source_file)
135
- modified_at = File.mtime(source_file)
136
- if workers[name] != modified_at
137
- logger.debug "Loading #{source_file}"
138
- load(source_file)
139
- workers[name] = modified_at
140
- end
141
- else
142
- raise SourceFileNotFound, "Source file not found: #{source_file}"
143
- end
144
-
145
- Object.const_get(camelize("#{name}_worker"))
146
- end
147
- end
148
- end
@@ -1,131 +0,0 @@
1
- module Refinery #:nodoc:
2
- # Publish events.
3
- class EventPublisher
4
- include Refinery::Loggable
5
- include Refinery::Configurable
6
- include Refinery::Queueable
7
- include Refinery::Utilities
8
-
9
- STARTING = 'starting' #:nodoc:
10
- RUNNING = 'running' #:nodoc:
11
- STOPPED = 'stopped' #:nodoc:
12
-
13
- attr_accessor :publishers_directory
14
-
15
- # Initialize the event publisher
16
- #
17
- # Options:
18
- # * <tt>:debug</tt>: Set to true to enable debug logging
19
- # * <tt>:config</tt>: Provide a file path to load that config
20
- def initialize(options={})
21
- logger.level = Logger::INFO if options[:verbose]
22
- logger.level = Logger::DEBUG if options[:debug]
23
- config.load_file(options[:config]) if options[:config]
24
- self.publishers_directory = options[:publishers] if options[:publishers]
25
- end
26
-
27
- # Get the event publisher state
28
- def state
29
- @state ||= STARTING
30
- end
31
-
32
- # Return true if the event publisher is running
33
- def running?
34
- state == RUNNING
35
- end
36
-
37
- # The directory where publishers are found. Defaults to ./publishers
38
- def publishers_directory
39
- @publishers_directory ||= './publishers'
40
- end
41
-
42
- # A hash of all publisher classes mapped to last modified timestamps.
43
- def publishers
44
- @publishers ||= {}
45
- end
46
-
47
- # Run the specified publisher once and return
48
- def run_once(key)
49
- prefix = config['prefix'] || ''
50
- settings = config['processors'][key]
51
- raise RuntimeError, "No processor configuration found for #{key}" unless settings
52
- queue_name = settings['queue'] || key
53
- queue_name = "#{prefix}#{queue_name}"
54
- waiting_queue_name = "#{queue_name}_waiting"
55
- logger.debug "Using queue #{waiting_queue_name}"
56
- load_publisher_class(key).new(waiting_queue_name).execute
57
- end
58
-
59
- # Run the event publisher
60
- def run
61
- @state = RUNNING
62
- logger.info "Starting event publisher"
63
- config['processors'].each do |key, settings|
64
- run_publisher(key, settings)
65
- end
66
-
67
- begin
68
- threads.each { |thread| thread.join }
69
- rescue Interrupt => e
70
- end
71
-
72
- logger.info "Exiting event publisher"
73
- end
74
-
75
- private
76
- # An array of threads, one for each publisher instance
77
- def threads
78
- @threads ||= []
79
- end
80
-
81
- # Run the publisher for the given key
82
- def run_publisher(key, settings)
83
- if File.exists?(source_file(key))
84
- prefix = config['prefix'] || ''
85
- logger.info "Creating publisher for #{key}"
86
- queue_name = settings['queue'] || key
87
- queue_name = "#{prefix}#{queue_name}"
88
- waiting_queue_name = "#{queue_name}_waiting"
89
- logger.debug "Using queue #{waiting_queue_name}"
90
-
91
- threads << Thread.new(waiting_queue_name, settings) do |waiting_queue_name, settings|
92
- while(running?)
93
- begin
94
- load_publisher_class(key).new(waiting_queue_name).execute
95
- rescue Exception => e
96
- logger.error "Error running publisher: #{e.message}"
97
- end
98
-
99
- delay = settings['publishers']['delay'] || 60
100
- logger.debug "Sleeping #{delay} seconds"
101
- sleep delay
102
-
103
- end
104
- end
105
- else
106
- logger.warn "No publisher found for #{key}"
107
- end
108
- end
109
-
110
- def source_file(key)
111
- source_file = "#{publishers_directory}/#{key}.rb"
112
- end
113
-
114
- def load_publisher_class(key)
115
- source_file = source_file(key)
116
- if File.exist?(source_file)
117
- modified_at = File.mtime(source_file)
118
- if publishers[key] != modified_at
119
- logger.debug "Loading #{source_file}"
120
- load(source_file)
121
- publishers[key] = modified_at
122
- end
123
- else
124
- raise SourceFileNotFound, "Source file not found: #{source_file}"
125
- end
126
-
127
- Object.const_get(camelize("#{key}_publisher"))
128
- end
129
-
130
- end
131
- end
@@ -1,33 +0,0 @@
1
- module Refinery #:nodoc:
2
- # A heartbeat publisher that indicates a server is alive.
3
- class Heartbeat
4
- include Refinery::Loggable
5
- include Refinery::Configurable
6
- include Refinery::Queueable
7
- include Refinery::Utilities
8
-
9
- # Initialize the heartbeat for the given server.
10
- def initialize(server)
11
- queue_prefix = config['prefix'] || ''
12
- @server = server
13
- @thread = Thread.new do
14
- if defined?(java.lang.Thread)
15
- java.lang.Thread.current_thread.name = 'Heartbeat'
16
- end
17
-
18
- loop do
19
- with_queue("#{queue_prefix}heartbeat") do |heartbeat_queue|
20
- logger.debug "Send heartbeat"
21
- message = {
22
- 'host_info' => host_info,
23
- 'timestamp' => Time.now.utc,
24
- 'running_daemons' => @server.daemons.length
25
- }
26
- heartbeat_queue.send_message(Base64.encode64(message.to_json))
27
- sleep(60)
28
- end
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,9 +0,0 @@
1
- module Refinery
2
- # Include this module to get access to the server logger
3
- module Loggable
4
- # Get the logger.
5
- def logger
6
- @logger ||= Refinery::Server.logger
7
- end
8
- end
9
- end
@@ -1,113 +0,0 @@
1
- module Refinery #:nodoc:
2
- # The monitor is responsible for monitoring the health of the various
3
- # components of refinery.
4
- class Monitor
5
- include Refinery::Loggable
6
- include Refinery::Configurable
7
- include Refinery::Queueable
8
- include Refinery::Utilities
9
-
10
- # Initialize the monitor.
11
- #
12
- # Options:
13
- # * <tt>:verbose</tt>: Enable INFO level logging
14
- # * <tt>:debug</tt>: Enable DEBUG level logging
15
- # * <tt>:config</tt>: The config file
16
- def initialize(options)
17
- logger.level = Logger::INFO if options[:verbose]
18
- logger.level = Logger::DEBUG if options[:debug]
19
- config.load_file(options[:config]) if options[:config]
20
- @queue_prefix = config['prefix'] || ''
21
- end
22
-
23
- # Execute the monitor. The monitor will start one heartbeat
24
- # monitor thread and one thread for each done queue and error
25
- # queue as specified in the configuration.
26
- def run
27
- logger.info "Starting up monitor"
28
- heartbeat_monitor_thread = run_heartbeat_monitor
29
- done_monitor_threads = run_done_monitors
30
- error_monitor_threads = run_error_monitors
31
-
32
- logger.info "Monitor running"
33
-
34
- Refinery::StatsServer.new.run
35
-
36
- begin
37
- heartbeat_monitor_thread.join
38
- done_monitor_threads.each { |t| t.join }
39
- error_monitor_threads.each { |t| t.join }
40
- rescue Interrupt => e
41
- end
42
-
43
- logger.info "Monitor is exiting"
44
- end
45
-
46
- private
47
- def statistics
48
- @statistics ||= Refinery::Statistics.new
49
- end
50
-
51
- def run_heartbeat_monitor
52
- logger.info "Starting #{@queue_prefix}heartbeat monitor"
53
- Thread.new("#{@queue_prefix}heartbeat") do |heartbeat_queue_name|
54
- loop do
55
- with_queue(heartbeat_queue_name) do |heartbeat_queue|
56
- while (message = heartbeat_queue.receive)
57
- logger.debug "#{heartbeat_queue.name}: #{decode_message(message.body).inspect}"
58
- message.delete()
59
- end
60
- end
61
- sleep(5)
62
- end
63
- end
64
- end
65
-
66
- def run_done_monitors
67
- config['processors'].collect do |key, settings|
68
- queue_name = settings['queue'] || key
69
- done_queue_name = "#{@queue_prefix}#{queue_name}_done"
70
- logger.debug "Starting monitor for queue #{done_queue_name}"
71
- Thread.new(done_queue_name) do |done_queue_name|
72
- loop do
73
- with_queue(done_queue_name) do |done_queue|
74
- while (message = done_queue.receive)
75
- done_message = decode_message(message.body)
76
- logger.debug "#{done_queue.name}: #{done_message.pretty_inspect}"
77
- processed = decode_message(done_message['original'])
78
- logger.info "Done: #{queue_name} #{processed.inspect}"
79
- message.delete()
80
- statistics.record_done(done_message)
81
- end
82
- sleep(5)
83
- end
84
- end
85
- end
86
- end
87
- end
88
-
89
- def run_error_monitors
90
- config['processors'].collect do |key, settings|
91
- queue_name = settings['queue'] || key
92
- error_queue_name = "#{@queue_prefix}#{queue_name}_error"
93
- logger.info "Starting error monitor for queue #{error_queue_name}"
94
- Thread.new(error_queue_name) do |error_queue_name|
95
- loop do
96
- with_queue(error_queue_name) do |error_queue|
97
- while (message = error_queue.receive)
98
- error_message = decode_message(message.body)
99
- logger.debug "#{error_queue.name}: #{error_message.pretty_inspect}"
100
- processed = decode_message(error_message['original'])
101
- logger.info "Error: #{queue_name} #{processed.inspect}"
102
- message.delete()
103
- statistics.record_error(error_message)
104
- end
105
- end
106
- sleep(5)
107
- end
108
- end
109
- end
110
- end
111
-
112
- end
113
- end