kodama 0.0.1 → 0.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.
data/README.md CHANGED
@@ -61,6 +61,9 @@ Kodama::Client.start(:host => '127.0.0.1', :username => 'user') do |c|
61
61
  c.connection_retry_limit = 100 # times
62
62
  c.connection_retry_wait = 3 # second
63
63
 
64
+ # Exit gracefully when kodama receives specified signals
65
+ c.gracefully_stop_on :QUIT, :INT
66
+
64
67
  c.on_query_event do |event|
65
68
  p event.query
66
69
  end
@@ -76,25 +79,17 @@ end
76
79
  ```ruby
77
80
  require 'rubygems'
78
81
  require 'kodama'
79
- require 'thread'
80
82
  require 'json'
81
83
  require 'redis'
82
84
 
83
85
  class Worker
84
- attr_accessor :queue
85
86
  def initialize
86
- @queue = Queue.new
87
87
  @redis = Redis.new
88
88
  end
89
89
 
90
- def start
91
- Thread.start do
92
- loop do
93
- event = @queue.pop
94
- record_id = get_row(event)[0] # first column is id
95
- @redis.set "#{event.table_name}_#{record_id}", event.rows.to_json
96
- end
97
- end
90
+ def perform(event)
91
+ record_id = get_row(event)[0] # first column is id
92
+ @redis.set "#{event.table_name}_#{record_id}", event.rows.to_json
98
93
  end
99
94
 
100
95
  def get_row(event)
@@ -109,13 +104,12 @@ end
109
104
 
110
105
 
111
106
  worker = Worker.new
112
- worker.start
113
107
 
114
108
  Kodama::Client.start(:host => '127.0.0.1', :username => 'user') do |c|
115
109
  c.binlog_position_file = 'position.log'
116
110
 
117
111
  c.on_row_event do |event|
118
- worker.queue << event
112
+ worker.perform(event)
119
113
  end
120
114
  end
121
115
  ```
@@ -136,6 +130,17 @@ It accepts ``:debug``, ``:info``, ``:warn``, ``:error``, ``:fatal``.
136
130
 
137
131
  If for some reason the connection to MySQL is terminated, Kodama will attempt to reconnect ``connection_retry_limit`` times, while waiting ``connection_retry_wait`` seconds between attempts.
138
132
 
133
+ ### gracefully_stop_on
134
+
135
+ Kodama traps specified signals and stop gracefully.
136
+ It accpets multiple signals like following.
137
+
138
+ ```ruby
139
+ Kodama::Client.start do |c|
140
+ c.gracefully_stop_on :INT, :QUIT
141
+ end
142
+ ```
143
+
139
144
  ## Authors
140
145
 
141
146
  Yusuke Mito, Genki Sugawara
@@ -33,6 +33,7 @@ module Kodama
33
33
  @retry_info = RetryInfo.new(:limit => 100, :wait => 3)
34
34
  @callbacks = {}
35
35
  @logger = Logger.new(STDOUT)
36
+ @safe_to_stop = true
36
37
 
37
38
  self.log_level = :info
38
39
  end
@@ -65,6 +66,18 @@ module Kodama
65
66
  @logger.level = LOG_LEVEL[level]
66
67
  end
67
68
 
69
+ def gracefully_stop_on(*signals)
70
+ signals.each do |signal|
71
+ Signal.trap(signal) do
72
+ if safe_to_stop?
73
+ exit(0)
74
+ else
75
+ stop_request
76
+ end
77
+ end
78
+ end
79
+ end
80
+
68
81
  def binlog_client(url)
69
82
  Binlog::Client.new(url)
70
83
  end
@@ -77,6 +90,14 @@ module Kodama
77
90
  @retry_info.count
78
91
  end
79
92
 
93
+ def safe_to_stop?
94
+ !!@safe_to_stop
95
+ end
96
+
97
+ def stop_request
98
+ @stop_requested = true
99
+ end
100
+
80
101
  def start
81
102
  begin
82
103
  client = binlog_client(@url)
@@ -88,36 +109,10 @@ module Kodama
88
109
  end
89
110
 
90
111
  while event = client.wait_for_next_event
91
- @binlog_info.position = event.next_position
92
- case event
93
- when Binlog::QueryEvent
94
- callback :on_query_event, event
95
- @binlog_info.save(@position_file)
96
- when Binlog::RotateEvent
97
- callback :on_rotate_event, event
98
- @binlog_info.filename = event.binlog_file
99
- @binlog_info.position = event.binlog_pos
100
- @binlog_info.save(@position_file)
101
- when Binlog::IntVarEvent
102
- callback :on_int_var_event, event
103
- when Binlog::UserVarEvent
104
- callback :on_user_var_event, event
105
- when Binlog::FormatEvent
106
- callback :on_format_event, event
107
- when Binlog::Xid
108
- callback :on_xid, event
109
- when Binlog::TableMapEvent
110
- callback :on_table_map_event, event
111
- when Binlog::RowEvent
112
- callback :on_row_event, event
113
- @binlog_info.save(@position_file)
114
- when Binlog::IncidentEvent
115
- callback :on_incident_event, event
116
- when Binlog::UnimplementedEvent
117
- callback :on_unimplemented_event, event
118
- else
119
- @logger.debug "Not Implemented: #{event.event_type}"
112
+ unsafe do
113
+ process_event(event)
120
114
  end
115
+ break if stop_requested?
121
116
  end
122
117
  rescue Binlog::Error => e
123
118
  @logger.debug e
@@ -131,6 +126,49 @@ module Kodama
131
126
  end
132
127
 
133
128
  private
129
+ def unsafe
130
+ @safe_to_stop = false
131
+ yield
132
+ @safe_to_stop = true
133
+ end
134
+
135
+ def stop_requested?
136
+ @stop_requested
137
+ end
138
+
139
+ def process_event(event)
140
+ @binlog_info.position = event.next_position
141
+ case event
142
+ when Binlog::QueryEvent
143
+ callback :on_query_event, event
144
+ @binlog_info.save(@position_file)
145
+ when Binlog::RotateEvent
146
+ callback :on_rotate_event, event
147
+ @binlog_info.filename = event.binlog_file
148
+ @binlog_info.position = event.binlog_pos
149
+ @binlog_info.save(@position_file)
150
+ when Binlog::IntVarEvent
151
+ callback :on_int_var_event, event
152
+ when Binlog::UserVarEvent
153
+ callback :on_user_var_event, event
154
+ when Binlog::FormatEvent
155
+ callback :on_format_event, event
156
+ when Binlog::Xid
157
+ callback :on_xid, event
158
+ when Binlog::TableMapEvent
159
+ callback :on_table_map_event, event
160
+ when Binlog::RowEvent
161
+ callback :on_row_event, event
162
+ @binlog_info.save(@position_file)
163
+ when Binlog::IncidentEvent
164
+ callback :on_incident_event, event
165
+ when Binlog::UnimplementedEvent
166
+ callback :on_unimplemented_event, event
167
+ else
168
+ @logger.error "Not Implemented: #{event.event_type}"
169
+ end
170
+ end
171
+
134
172
  def callback(name, *args)
135
173
  if @callbacks[name]
136
174
  instance_exec *args, &@callbacks[name]
@@ -1,3 +1,3 @@
1
1
  module Kodama
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -106,7 +106,7 @@ describe Kodama::Client do
106
106
  }.to yield_with_args(row_event)
107
107
  end
108
108
 
109
- it 'position is saved only on row, query and rotate event' do
109
+ it 'should save position only on row, query and rotate event' do
110
110
  stub_binlog_client([rotate_event, query_event, row_event, xid_event])
111
111
  position_file = TestPositionFile.new.tap do |pf|
112
112
  pf.should_receive(:update).with('binlog', 100).once.ordered
@@ -118,12 +118,21 @@ describe Kodama::Client do
118
118
  client.start
119
119
  end
120
120
 
121
- it 'retry exactly specifeid times' do
121
+ it 'should retry exactly specifeid times' do
122
122
  stub_binlog_client([query_event], false)
123
123
  client.connection_retry_limit = 2
124
124
  client.connection_retry_wait = 0.1
125
125
  expect { client.start }.to raise_error(Binlog::Error)
126
126
  client.connection_retry_count.should == 2
127
127
  end
128
+
129
+ it 'should stop when it receives stop request' do
130
+ stub_binlog_client([query_event, row_event])
131
+ client.on_query_event do |event|
132
+ self.stop_request
133
+ end
134
+ expect {|block| client.on_row_event(&block) }.not_to yield_control
135
+ client.start
136
+ end
128
137
  end
129
138
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kodama
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 0
9
8
  - 1
10
- version: 0.0.1
9
+ - 0
10
+ version: 0.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Yusuke Mito
@@ -15,12 +15,10 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-11-28 00:00:00 Z
18
+ date: 2012-12-04 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: ruby-binlog
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
21
+ version_requirements: &id001 !ruby/object:Gem::Requirement
24
22
  none: false
25
23
  requirements:
26
24
  - - ">="
@@ -31,12 +29,12 @@ dependencies:
31
29
  - 1
32
30
  - 8
33
31
  version: 0.1.8
32
+ prerelease: false
34
33
  type: :runtime
35
- version_requirements: *id001
34
+ name: ruby-binlog
35
+ requirement: *id001
36
36
  - !ruby/object:Gem::Dependency
37
- name: rake
38
- prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
37
+ version_requirements: &id002 !ruby/object:Gem::Requirement
40
38
  none: false
41
39
  requirements:
42
40
  - - ">="
@@ -45,12 +43,12 @@ dependencies:
45
43
  segments:
46
44
  - 0
47
45
  version: "0"
46
+ prerelease: false
48
47
  type: :development
49
- version_requirements: *id002
48
+ name: rake
49
+ requirement: *id002
50
50
  - !ruby/object:Gem::Dependency
51
- name: rspec
52
- prerelease: false
53
- requirement: &id003 !ruby/object:Gem::Requirement
51
+ version_requirements: &id003 !ruby/object:Gem::Requirement
54
52
  none: false
55
53
  requirements:
56
54
  - - ">="
@@ -59,12 +57,12 @@ dependencies:
59
57
  segments:
60
58
  - 0
61
59
  version: "0"
60
+ prerelease: false
62
61
  type: :development
63
- version_requirements: *id003
62
+ name: rspec
63
+ requirement: *id003
64
64
  - !ruby/object:Gem::Dependency
65
- name: pry
66
- prerelease: false
67
- requirement: &id004 !ruby/object:Gem::Requirement
65
+ version_requirements: &id004 !ruby/object:Gem::Requirement
68
66
  none: false
69
67
  requirements:
70
68
  - - ">="
@@ -73,12 +71,12 @@ dependencies:
73
71
  segments:
74
72
  - 0
75
73
  version: "0"
74
+ prerelease: false
76
75
  type: :development
77
- version_requirements: *id004
76
+ name: pry
77
+ requirement: *id004
78
78
  - !ruby/object:Gem::Dependency
79
- name: pry-nav
80
- prerelease: false
81
- requirement: &id005 !ruby/object:Gem::Requirement
79
+ version_requirements: &id005 !ruby/object:Gem::Requirement
82
80
  none: false
83
81
  requirements:
84
82
  - - ">="
@@ -87,12 +85,12 @@ dependencies:
87
85
  segments:
88
86
  - 0
89
87
  version: "0"
88
+ prerelease: false
90
89
  type: :development
91
- version_requirements: *id005
90
+ name: pry-nav
91
+ requirement: *id005
92
92
  - !ruby/object:Gem::Dependency
93
- name: guard-rspec
94
- prerelease: false
95
- requirement: &id006 !ruby/object:Gem::Requirement
93
+ version_requirements: &id006 !ruby/object:Gem::Requirement
96
94
  none: false
97
95
  requirements:
98
96
  - - "="
@@ -103,12 +101,12 @@ dependencies:
103
101
  - 1
104
102
  - 2
105
103
  version: 2.1.2
104
+ prerelease: false
106
105
  type: :development
107
- version_requirements: *id006
106
+ name: guard-rspec
107
+ requirement: *id006
108
108
  - !ruby/object:Gem::Dependency
109
- name: rb-fsevent
110
- prerelease: false
111
- requirement: &id007 !ruby/object:Gem::Requirement
109
+ version_requirements: &id007 !ruby/object:Gem::Requirement
112
110
  none: false
113
111
  requirements:
114
112
  - - ~>
@@ -119,8 +117,10 @@ dependencies:
119
117
  - 9
120
118
  - 1
121
119
  version: 0.9.1
120
+ prerelease: false
122
121
  type: :development
123
- version_requirements: *id007
122
+ name: rb-fsevent
123
+ requirement: *id007
124
124
  description: ruby-binlog based MySQL replication listener
125
125
  email:
126
126
  - y310.1984@gmail.com