processor 0.0.0.beta → 0.0.0.initial

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.
@@ -1,3 +1,3 @@
1
1
  module Processor
2
- VERSION = "0.0.0.beta"
2
+ VERSION = "0.0.0.initial"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: processor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0.beta
4
+ version: 0.0.0.initial
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-02 00:00:00.000000000 Z
12
+ date: 2013-04-30 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -67,29 +67,15 @@ extensions: []
67
67
  extra_rdoc_files: []
68
68
  files:
69
69
  - .gitignore
70
- - .rspec
71
70
  - .rvmrc
72
71
  - .travis.yml
73
72
  - Gemfile
74
73
  - LICENSE
75
74
  - README.md
76
75
  - Rakefile
77
- - example/example_runner.rb
78
- - example/migration.rb
79
- - example/observer/progress_bar.rb
80
- - example/simple_runner.rb
81
76
  - lib/processor.rb
82
- - lib/processor/data_processor.rb
83
- - lib/processor/events_registrator.rb
84
- - lib/processor/observer/logger.rb
85
- - lib/processor/observer/null_observer.rb
86
- - lib/processor/thread_runner.rb
87
77
  - lib/processor/version.rb
88
78
  - processor.gemspec
89
- - spec/example_spec.rb
90
- - spec/processor/events_registrator_spec.rb
91
- - spec/processor/observer/logger_spec.rb
92
- - spec/processor/thread_runner_spec.rb
93
79
  - spec/spec_helper_lite.rb
94
80
  homepage: http://github.com/AlexParamonov/processor
95
81
  licenses:
@@ -117,8 +103,4 @@ signing_key:
117
103
  specification_version: 3
118
104
  summary: Process records one by one
119
105
  test_files:
120
- - spec/example_spec.rb
121
- - spec/processor/events_registrator_spec.rb
122
- - spec/processor/observer/logger_spec.rb
123
- - spec/processor/thread_runner_spec.rb
124
106
  - spec/spec_helper_lite.rb
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --colour
2
- --format documentation
@@ -1,43 +0,0 @@
1
- require 'processor/thread_runner'
2
- require 'processor/observer/logger'
3
-
4
- module Processor
5
- module Example
6
- class ExampleRunner < ThreadRunner
7
- def initialize
8
- # Logger could be a lambda
9
- # logger = -> name do
10
- # ::Logger.new("log/debug_#{name}_daily.log", "daily").tap do |logger|
11
- # logger.datetime_format = "%H:%M:%S"
12
- # logger.level = ::Logger::DEBUG
13
- # end
14
- # end
15
-
16
- # logger could be an instance of Ruby Logger
17
- logger = ::Logger.new(STDOUT).tap do |logger|
18
- logger.level = ::Logger::DEBUG
19
- logger.formatter = -> _, _, _, msg do
20
- "log < #{msg}\n"
21
- end
22
- end
23
-
24
- # logger could be an instance of Rails Logger
25
- # logger = Rails.logger
26
- # Or be nil
27
- # logger = nil
28
- # in this case logger will be initialized as Ruby Logger and write to log/name_of_processor_time_stamp.log
29
-
30
- # messenger could be an instance of Ruby Logger
31
- messenger = ::Logger.new(STDOUT).tap do |logger|
32
- logger.formatter = -> _, _, _, msg do
33
- "message > #{msg}\n"
34
- end
35
- logger.level = ::Logger::INFO
36
- end
37
-
38
- logger_observer = Processor::Observer::Logger.new(logger, messenger: messenger)
39
- super logger_observer
40
- end
41
- end
42
- end
43
- end
data/example/migration.rb DELETED
@@ -1,29 +0,0 @@
1
- require 'processor/data_processor'
2
-
3
- module Processor
4
- module Example
5
- class Migration < DataProcessor
6
- attr_reader :records
7
- def initialize(records)
8
- @records = records
9
- end
10
-
11
- def done?(records)
12
- records.count < 1
13
- end
14
-
15
- def process(record)
16
- record.do_something
17
- "OK"
18
- end
19
-
20
- def fetch_records
21
- records.shift(2)
22
- end
23
-
24
- def total_records
25
- records.count
26
- end
27
- end
28
- end
29
- end
@@ -1,26 +0,0 @@
1
- require 'processor/observer/null_observer'
2
- require 'progressbar'
3
-
4
- module Processor
5
- module Example
6
- module Observer
7
- class ProgressBar < Processor::Observer::NullObserver
8
- def processing_started
9
- @progress_bar = ::ProgressBar.new("Records", processor.total_records)
10
- messenger.debug "Initialized ProgressBar with #{processor.total_records} records"
11
- end
12
-
13
- def before_record_processing(record)
14
- progress_bar.inc
15
- end
16
-
17
- def processing_finished
18
- progress_bar.finish
19
- end
20
-
21
- private
22
- attr_reader :progress_bar
23
- end
24
- end
25
- end
26
- end
@@ -1,12 +0,0 @@
1
- require 'processor/thread_runner'
2
- require 'processor/observer/logger'
3
-
4
- module Processor
5
- module Example
6
- class SimpleRunner < ThreadRunner
7
- def initialize
8
- super Processor::Observer::Logger.new
9
- end
10
- end
11
- end
12
- end
@@ -1,28 +0,0 @@
1
- module Processor
2
- class DataProcessor
3
- def done?(records)
4
- records.count < 1
5
- end
6
-
7
- def process(record)
8
- raise NotImplementedError
9
- end
10
-
11
- def fetch_records
12
- raise NotImplementedError
13
- end
14
-
15
- def total_records
16
- raise NotImplementedError
17
- end
18
-
19
- def name
20
- # underscore a class name
21
- self.class.name.to_s.
22
- gsub(/::/, '_').
23
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
24
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
25
- downcase
26
- end
27
- end
28
- end
@@ -1,16 +0,0 @@
1
- module Processor
2
- class EventsRegistrator
3
- def initialize(observers)
4
- @observers = observers
5
- end
6
-
7
- def register(event, *data)
8
- observers.each do |observer|
9
- observer.update event, *data
10
- end
11
- end
12
-
13
- private
14
- attr_reader :observers
15
- end
16
- end
@@ -1,98 +0,0 @@
1
- require_relative 'null_observer'
2
- require 'logger'
3
-
4
- module Processor
5
- module Observer
6
- class Logger < NullObserver
7
- def initialize(logger = nil, options = {})
8
- @logger_source = logger
9
- super options
10
- end
11
-
12
- def processing_started(processor)
13
- initialize_logger(processor)
14
-
15
- message = "Processing of #{processor.name} started."
16
- logger.info message
17
- messenger.info message
18
-
19
- message = <<-MESSAGE.gsub(/^\s+/, '')
20
- Proggress will be saved to the log file. Run
21
- tail -f #{log_file_name}
22
- to see log in realtime
23
- MESSAGE
24
- messenger.info message if use_log_file?
25
- end
26
-
27
- def before_record_processing(record)
28
- message = "Record #{id_for record} is going to be processed"
29
- logger.debug message
30
- messenger.debug message
31
- end
32
-
33
- def after_record_processing(record, result)
34
- message = "Successfully processed #{id_for record}: #{result}"
35
- logger.info message
36
- messenger.debug message
37
- end
38
-
39
- def processing_finished(processor)
40
- message = "Processing of #{processor.name} finished."
41
- logger.info message
42
- messenger.info message
43
- messenger.info "Log file saved to #{log_file_name}" if use_log_file?
44
- end
45
-
46
- def record_processing_error(record, exception)
47
- message = "Error processing #{id_for record}: #{exception}"
48
- logger.error message
49
- messenger.error message
50
- end
51
-
52
- def processing_error(processor, exception)
53
- message = "Processing #{processor.name} failed: #{exception}"
54
- logger.fatal message
55
- messenger.fatal message
56
- end
57
-
58
- private
59
- attr_reader :logger, :log_file_name
60
-
61
- def initialize_logger(processor)
62
- @logger =
63
- if @logger_source.is_a? Proc
64
- @logger_source.call processor.name
65
- else
66
- @logger_source or ::Logger.new(create_log_filename(processor.name)).tap do |logger|
67
- logger.level = ::Logger::INFO
68
- end
69
- end
70
- end
71
-
72
- def create_log_filename(processor_name)
73
- @log_file_name = "log/#{processor_name}_on_#{current_time_string}.log"
74
- end
75
-
76
- def use_log_file?
77
- not log_file_name.nil?
78
- end
79
-
80
- def current_time_string
81
- Time.now.gmtime.strftime "%Y-%m-%d_%H%M%S_UTC"
82
- end
83
-
84
- def id_for record
85
- [:uid, :id, :to_token, :token, :to_sym].each do |method|
86
- return record.public_send method if record.respond_to? method
87
- end
88
-
89
- [:uid, :id, :token, :sym, :UID, :ID, :TOKEN, :SYM].each do |method|
90
- return record[method] if record.key? method
91
- return record[method.to_s] if record.key? method.to_s
92
- end if record.respond_to?(:key?) && record.respond_to?(:[])
93
-
94
- record.to_s
95
- end
96
- end
97
- end
98
- end
@@ -1,23 +0,0 @@
1
- require 'logger'
2
-
3
- module Processor
4
- module Observer
5
- class NullObserver
6
- def initialize(options = {})
7
- @messenger = options.fetch :messenger do
8
- ::Logger.new(STDOUT).tap do |logger|
9
- logger.formatter = -> _, _, _, msg do
10
- "> #{msg}\n"
11
- end
12
- end
13
- end
14
- end
15
-
16
- def method_missing(*); end
17
- alias_method :update, :send
18
-
19
- private
20
- attr_reader :messenger
21
- end
22
- end
23
- end
@@ -1,59 +0,0 @@
1
- require_relative "events_registrator"
2
-
3
- module Processor
4
- class ThreadRunner
5
- def initialize(*observers)
6
- @observers = observers
7
- end
8
-
9
- # This method is thread-safe. But not observers.
10
- # Consider creating new runner for a thread or use thread safe observers
11
- def run(processor)
12
- events = events_registrator
13
- events.register :processing_started, processor
14
-
15
- records_ran = 0
16
- until processor.done?(records = processor.fetch_records)
17
- threads = []
18
- begin
19
- records.each do |record|
20
- recursion_preventer processor do
21
- records_ran += 1
22
- end
23
-
24
- threads << Thread.new(processor, record) do |thread_data_processor, thread_record|
25
- begin
26
- events.register :before_record_processing, thread_record
27
-
28
- result = thread_data_processor.process(thread_record)
29
-
30
- events.register :after_record_processing, thread_record, result
31
- rescue RuntimeError => exception
32
- events.register :record_processing_error, thread_record, exception
33
- end
34
- end
35
- end
36
- ensure # join already created threads even if recursion was detected
37
- threads.each(&:join)
38
- end
39
- end
40
-
41
- events.register :processing_finished, processor
42
- rescue Exception => exception
43
- events.register :processing_error, processor, exception
44
- raise exception
45
- end
46
-
47
- private
48
- attr_reader :observers
49
-
50
- def recursion_preventer(processor)
51
- counter = yield
52
- raise Exception, "Processing fall into recursion. Check logs." if counter > (processor.total_records * 1.1).round + 10
53
- end
54
-
55
- def events_registrator
56
- EventsRegistrator.new observers
57
- end
58
- end
59
- end
data/spec/example_spec.rb DELETED
@@ -1,24 +0,0 @@
1
- require 'spec_helper_lite'
2
- require_relative '../example/example_runner'
3
- require_relative '../example/migration'
4
- require 'fileutils'
5
-
6
- describe "Example" do
7
- before(:each) do
8
- records = %w[item1 item2 item3 item4 item5]
9
- records.each do |record|
10
- record.should_receive(:do_something).once
11
- end
12
- @migration = Processor::Example::Migration.new records
13
- end
14
-
15
- it "should use logger and messenger" do
16
- migration_runner = Processor::Example::ExampleRunner.new
17
- migration_runner.run @migration
18
- end
19
-
20
- it "should run without configuration" do
21
- runner = Processor::ThreadRunner.new
22
- runner.run @migration
23
- end
24
- end
@@ -1,15 +0,0 @@
1
- require 'spec_helper_lite'
2
- require 'processor/events_registrator'
3
-
4
- describe Processor::EventsRegistrator do
5
- subject { Processor::EventsRegistrator }
6
-
7
- it "should broadcast events to all observers" do
8
- observers = 3.times.map do
9
- stub(:observer).tap { |observer| observer.should_receive(:update).with(:test_event).once }
10
- end
11
-
12
- events = subject.new(observers)
13
- events.register :test_event
14
- end
15
- end
@@ -1,32 +0,0 @@
1
- require 'spec_helper_lite'
2
- require 'processor/observer/logger'
3
-
4
- describe Processor::Observer::Logger do
5
- let(:processor) { stub.as_null_object }
6
- let(:no_messages) { ::Logger.new("/dev/null") }
7
-
8
- subject { Processor::Observer::Logger }
9
- it "accepts logger builder as parameter" do
10
- external_logger = mock
11
- logger_observer = subject.new -> name { external_logger }, messenger: no_messages
12
-
13
- external_logger.should_receive(:info)
14
- logger_observer.processing_started processor
15
- end
16
-
17
- it "accepts logger as parameter" do
18
- external_logger = mock
19
- logger_observer = subject.new external_logger, messenger: no_messages
20
-
21
- external_logger.should_receive(:info)
22
- logger_observer.processing_started processor
23
- end
24
-
25
- it "use ruby Logger if no external logger provided" do
26
- logger_observer = subject.new nil, messenger: no_messages
27
-
28
- Logger.should_receive(:new).and_return(stub.as_null_object)
29
- logger_observer.processing_started processor
30
- end
31
- end
32
-
@@ -1,134 +0,0 @@
1
- require 'spec_helper_lite'
2
- require 'processor/thread_runner'
3
-
4
- processor = Class.new do
5
- def done?(records)
6
- records.count < 1
7
- end
8
-
9
- def total_records
10
- 10
11
- end
12
- end.new
13
-
14
- describe Processor::ThreadRunner do
15
- let(:runner) { Processor::ThreadRunner.new }
16
- let(:events_registrator) { stub.as_null_object }
17
- before(:each) do
18
- runner.stub(events_registrator: events_registrator)
19
- end
20
-
21
- it "should fetch records from processor till it'll be done" do
22
- processor.stub(:done?).and_return(false, false, true)
23
- processor.should_receive(:fetch_records).exactly(3).times.and_return([])
24
- runner.run processor
25
- end
26
-
27
- it "should send each found record to processor" do
28
- records = [mock(:one), mock(:two), mock(:three)]
29
- records.each { |record| processor.should_receive(:process).with(record) }
30
-
31
- processor.stub(:fetch_records).and_return(records, [])
32
- runner.run processor
33
- end
34
-
35
- describe "exception handling" do
36
- let(:record) { stub }
37
- before(:each) do
38
- processor.stub(:fetch_records).and_return([record], [record], [])
39
- end
40
-
41
- describe "processing a record raised RuntimeError" do
42
- it "should continue processing" do
43
- processor.should_receive(:process).twice.and_raise(RuntimeError)
44
- expect { runner.run processor }.to_not raise_error
45
- end
46
-
47
- it "should register a record_processing_error event" do
48
- event_registered = false
49
- events_registrator.should_receive(:register) do |event_name, failed_record, exception|
50
- next if event_name != :record_processing_error
51
- event_name.should eq :record_processing_error
52
- failed_record.should eq record
53
- exception.should be_a RuntimeError
54
- event_registered = true
55
- end.any_number_of_times
56
-
57
- processor.stub(:process).and_raise(RuntimeError)
58
-
59
- begin
60
- runner.run processor
61
- rescue Exception; end
62
- event_registered.should be_true
63
- end
64
- end
65
-
66
- describe "processing a record raised Exception" do
67
- it "should break processing and rerise Exception" do
68
- custom_exception = Class.new Exception
69
- processor.should_receive(:process).once.and_raise(custom_exception)
70
- expect { runner.run processor }.to raise_error(custom_exception)
71
- end
72
-
73
- it "should register a processing_error event" do
74
- event_registered = false
75
- events_registrator.should_receive(:register) do |event_name, current_processor, exception|
76
- next if event_name != :processing_error
77
- event_name.should eq :processing_error
78
- current_processor.should eq processor
79
- exception.should be_a Exception
80
- event_registered = true
81
- end.any_number_of_times
82
-
83
- processor.stub(:process).and_raise(Exception)
84
-
85
- begin
86
- runner.run processor
87
- rescue Exception; end
88
- event_registered.should be_true
89
- end
90
- end
91
-
92
- describe "fetching records raised" do
93
- it "should break processing and rerise Exception" do
94
- custom_exception = Class.new RuntimeError
95
- processor.stub(:fetch_records).and_raise(custom_exception)
96
- processor.should_not_receive(:process)
97
- expect { runner.run processor }.to raise_error(custom_exception)
98
- end
99
-
100
- it "should register a processing_error" do
101
- event_registered = false
102
- events_registrator.should_receive(:register) do |event_name, processor, exception|
103
- next if event_name != :processing_error
104
- event_name.should eq :processing_error
105
- exception.should be_a RuntimeError
106
- event_registered = true
107
- end.any_number_of_times
108
-
109
- processor.stub(:fetch_records).and_raise(RuntimeError)
110
-
111
- begin
112
- runner.run processor
113
- rescue Exception; end
114
- event_registered.should be_true
115
- end
116
- end
117
- end
118
-
119
- describe "recursion" do
120
- it "should not allow infinit recursion" do
121
- processor.stub(:fetch_records).and_return([:one, :two])
122
- processor.should_receive(:process).at_most(100).times
123
- expect { runner.run processor }.to raise_error(Exception, /Processing fall into recursion/)
124
- end
125
-
126
- it "should have 10% + 10 rerurns window" do
127
- processor.stub(total_records: 100)
128
- processor.stub(:fetch_records).and_return([:one, :two])
129
- processor.should_receive(:process).exactly(120).times
130
- expect { runner.run processor }.to raise_error(Exception, /Processing fall into recursion/)
131
- end
132
- end
133
- end
134
-