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 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