kodama 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +18 -13
- data/lib/kodama/client.rb +67 -29
- data/lib/kodama/version.rb +1 -1
- data/spec/lib/client_spec.rb +11 -2
- metadata +32 -32
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
|
91
|
-
|
92
|
-
|
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.
|
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
|
data/lib/kodama/client.rb
CHANGED
@@ -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
|
-
|
92
|
-
|
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]
|
data/lib/kodama/version.rb
CHANGED
data/spec/lib/client_spec.rb
CHANGED
@@ -106,7 +106,7 @@ describe Kodama::Client do
|
|
106
106
|
}.to yield_with_args(row_event)
|
107
107
|
end
|
108
108
|
|
109
|
-
it '
|
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:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
- 0
|
9
8
|
- 1
|
10
|
-
|
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-
|
18
|
+
date: 2012-12-04 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
|
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
|
-
|
34
|
+
name: ruby-binlog
|
35
|
+
requirement: *id001
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
|
-
|
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
|
-
|
48
|
+
name: rake
|
49
|
+
requirement: *id002
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
|
-
|
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
|
-
|
62
|
+
name: rspec
|
63
|
+
requirement: *id003
|
64
64
|
- !ruby/object:Gem::Dependency
|
65
|
-
|
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
|
-
|
76
|
+
name: pry
|
77
|
+
requirement: *id004
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
|
-
|
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
|
-
|
90
|
+
name: pry-nav
|
91
|
+
requirement: *id005
|
92
92
|
- !ruby/object:Gem::Dependency
|
93
|
-
|
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
|
-
|
106
|
+
name: guard-rspec
|
107
|
+
requirement: *id006
|
108
108
|
- !ruby/object:Gem::Dependency
|
109
|
-
|
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
|
-
|
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
|