racecar 0.1.4 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +37 -2
- data/exe/racecar +2 -0
- data/exe/racecarctl +6 -0
- data/lib/racecar/cli.rb +2 -22
- data/lib/racecar/config.rb +22 -3
- data/lib/racecar/config_loader.rb +29 -0
- data/lib/racecar/consumer.rb +8 -3
- data/lib/racecar/ctl.rb +58 -0
- data/lib/racecar/runner.rb +5 -4
- data/lib/racecar/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63f11732ede854b710bf164d64cd1815e1edf588
|
4
|
+
data.tar.gz: 2f4451111982eaa874334ae309c8e6063fbd6bea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ccc72f3e1e5e76f4c16f20451a281cd7640c4a643a75dea4c4100e41e071433a2a3c297cc06bfcb8fdcf066a22b20e8856176d2a238bb79ca241b42bbd8fd1f
|
7
|
+
data.tar.gz: b9a03db77deaae0e50e17822931ce0e46b1f499ce80b9edfaee82bd334115cc226041f9a138bc87266ade1b29fbcf5f2e97d1b12fbefce432b8e236aaa0bf3c5
|
data/README.md
CHANGED
@@ -116,13 +116,48 @@ The possible configuration keys are:
|
|
116
116
|
* `offset_commit_interval` (_optional_) – How often to save the consumer's position in Kafka.
|
117
117
|
* `heartbeat_interval` (_optional_) – How often to send a heartbeat message to Kafka.
|
118
118
|
* `pause_timeout` (_optional_) – How long to pause a partition for if the consumer raises an exception while processing a message.
|
119
|
-
* `connect_timeout` (_optional_) – How long to wait when trying to connect to a Kafka broker.
|
120
|
-
* `socket_timeout` (_optional_) – How long to wait when trying to communicate with a Kafka broker.
|
119
|
+
* `connect_timeout` (_optional_) – How long to wait when trying to connect to a Kafka broker. Default is 10 seconds.
|
120
|
+
* `socket_timeout` (_optional_) – How long to wait when trying to communicate with a Kafka broker. Default is 30 seconds.
|
121
|
+
* `max_wait_time` (_optional_) – How long to allow the Kafka brokers to wait before returning messages. A higher number means larger batches, at the cost of higher latency. Default is 5 seconds.
|
121
122
|
|
122
123
|
Note that many of these configuration keys correspond directly with similarly named concepts in [ruby-kafka](https://github.com/zendesk/ruby-kafka) for more details on low-level operations, read that project's documentation.
|
123
124
|
|
124
125
|
It's also possible to configure Racecar using environment variables. For any given configuration key, there should be a corresponding environment variable with the prefix `RACECAR_`, in upper case. For instance, in order to configure the client id, set `RACECAR_CLIENT_ID=some-id` in the process in which the Racecar consumer is launched. You can set `brokers` by passing a comma-separated list, e.g. `RACECAR_BROKERS=kafka1:9092,kafka2:9092,kafka3:9092`.
|
125
126
|
|
127
|
+
### Testing consumers
|
128
|
+
|
129
|
+
Since consumers are merely classes that implement a simple interface, they're dead simple to test.
|
130
|
+
|
131
|
+
Here's an example of testing a consumer class using [RSpec](http://rspec.info/) and Rails:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
# app/consumers/create_contacts_consumer.rb
|
135
|
+
#
|
136
|
+
# Creates a Contact whenever an email address is written to the
|
137
|
+
# `email-addresses` topic.
|
138
|
+
class CreateContactsConsumer < Racecar::Consumer
|
139
|
+
subscribes_to "email-addresses"
|
140
|
+
|
141
|
+
def process(message)
|
142
|
+
email = message.value
|
143
|
+
|
144
|
+
Contact.create!(email: email)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# spec/consumers/create_contacts_consumer_spec.rb
|
149
|
+
describe CreateContactsConsumer do
|
150
|
+
it "creates a Contact for each email address in the topic" do
|
151
|
+
message = double("message", value: "john@example.com")
|
152
|
+
consumer = CreateContactsConsumer.new
|
153
|
+
|
154
|
+
consumer.process(message)
|
155
|
+
|
156
|
+
expect(Contact.where(email: "john@example.com")).to exist
|
157
|
+
end
|
158
|
+
end
|
159
|
+
```
|
160
|
+
|
126
161
|
## Development
|
127
162
|
|
128
163
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/exe/racecar
CHANGED
data/exe/racecarctl
ADDED
data/lib/racecar/cli.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "optparse"
|
2
|
+
require "racecar/config_loader"
|
2
3
|
|
3
4
|
module Racecar
|
4
5
|
module Cli
|
@@ -20,31 +21,10 @@ module Racecar
|
|
20
21
|
parser.parse!(args)
|
21
22
|
|
22
23
|
consumer_name = args.first or raise Racecar::Error, "no consumer specified"
|
23
|
-
config_file = "config/racecar.yml"
|
24
24
|
|
25
25
|
puts "=> Starting Racecar consumer #{consumer_name}..."
|
26
26
|
|
27
|
-
|
28
|
-
require "rails"
|
29
|
-
|
30
|
-
puts "=> Detected Rails, booting application..."
|
31
|
-
|
32
|
-
require "./config/environment"
|
33
|
-
|
34
|
-
Racecar.config.load_file(config_file, Rails.env)
|
35
|
-
|
36
|
-
if Racecar.config.log_to_stdout
|
37
|
-
# Write to STDOUT as well as to the log file.
|
38
|
-
console = ActiveSupport::Logger.new($stdout)
|
39
|
-
console.formatter = Rails.logger.formatter
|
40
|
-
console.level = Rails.logger.level
|
41
|
-
Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
|
42
|
-
end
|
43
|
-
|
44
|
-
Racecar.logger = Rails.logger
|
45
|
-
rescue LoadError
|
46
|
-
# Not a Rails application.
|
47
|
-
end
|
27
|
+
ConfigLoader.load!
|
48
28
|
|
49
29
|
# Find the consumer class by name.
|
50
30
|
consumer_class = Kernel.const_get(consumer_name)
|
data/lib/racecar/config.rb
CHANGED
@@ -45,10 +45,21 @@ module Racecar
|
|
45
45
|
# Default is to not pause partitions on processing errors.
|
46
46
|
pause_timeout: 0,
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
# Default is to allow at most 10 seconds when connecting to a broker.
|
49
|
+
connect_timeout: 10,
|
50
|
+
|
51
|
+
# Default is to allow at most 30 seconds when reading or writing to
|
52
|
+
# a broker socket.
|
53
|
+
socket_timeout: 30,
|
54
|
+
|
55
|
+
# Default is to allow the brokers up to 5 seconds before returning
|
56
|
+
# messages.
|
51
57
|
max_wait_time: 5,
|
58
|
+
|
59
|
+
# Default is to do nothing on exceptions.
|
60
|
+
error_handler: proc {},
|
61
|
+
|
62
|
+
# Default is to only log to the logger.
|
52
63
|
log_to_stdout: false,
|
53
64
|
}
|
54
65
|
|
@@ -65,6 +76,14 @@ module Racecar
|
|
65
76
|
raise ConfigError, "required configuration key `#{key}` not defined"
|
66
77
|
end
|
67
78
|
end
|
79
|
+
|
80
|
+
if socket_timeout <= max_wait_time
|
81
|
+
raise ConfigError, "`socket_timeout` must be longer than `max_wait_time`"
|
82
|
+
end
|
83
|
+
|
84
|
+
if connect_timeout <= max_wait_time
|
85
|
+
raise ConfigError, "`connect_timeout` must be longer than `max_wait_time`"
|
86
|
+
end
|
68
87
|
end
|
69
88
|
|
70
89
|
def load_file(path, environment)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Racecar
|
2
|
+
module ConfigLoader
|
3
|
+
def self.load!
|
4
|
+
config_file = "config/racecar.yml"
|
5
|
+
|
6
|
+
begin
|
7
|
+
require "rails"
|
8
|
+
|
9
|
+
puts "=> Detected Rails, booting application..."
|
10
|
+
|
11
|
+
require "./config/environment"
|
12
|
+
|
13
|
+
Racecar.config.load_file(config_file, Rails.env)
|
14
|
+
|
15
|
+
if Racecar.config.log_to_stdout
|
16
|
+
# Write to STDOUT as well as to the log file.
|
17
|
+
console = ActiveSupport::Logger.new($stdout)
|
18
|
+
console.formatter = Rails.logger.formatter
|
19
|
+
console.level = Rails.logger.level
|
20
|
+
Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
|
21
|
+
end
|
22
|
+
|
23
|
+
Racecar.logger = Rails.logger
|
24
|
+
rescue LoadError
|
25
|
+
# Not a Rails application.
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/racecar/consumer.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Racecar
|
2
2
|
class Consumer
|
3
|
-
Subscription = Struct.new(:topic, :start_from_beginning)
|
3
|
+
Subscription = Struct.new(:topic, :start_from_beginning, :max_bytes_per_partition)
|
4
4
|
|
5
5
|
class << self
|
6
6
|
attr_accessor :max_wait_time
|
@@ -11,9 +11,14 @@ module Racecar
|
|
11
11
|
end
|
12
12
|
|
13
13
|
# Adds one or more topic subscriptions.
|
14
|
-
|
14
|
+
#
|
15
|
+
# start_from_beginning - whether to start from the beginning or the end of each
|
16
|
+
# partition.
|
17
|
+
# max_bytes_per_partition - the maximum number of bytes to fetch from each partition
|
18
|
+
# at a time.
|
19
|
+
def subscribes_to(*topics, start_from_beginning: true, max_bytes_per_partition: 1048576)
|
15
20
|
topics.each do |topic|
|
16
|
-
subscriptions << Subscription.new(topic, start_from_beginning)
|
21
|
+
subscriptions << Subscription.new(topic, start_from_beginning, max_bytes_per_partition)
|
17
22
|
end
|
18
23
|
end
|
19
24
|
end
|
data/lib/racecar/ctl.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require "racecar/config_loader"
|
3
|
+
|
4
|
+
module Racecar
|
5
|
+
class Ctl
|
6
|
+
ProduceMessage = Struct.new(:value, :key, :topic)
|
7
|
+
|
8
|
+
def self.main(args)
|
9
|
+
command = args.shift or raise Racecar::Error, "no command specified"
|
10
|
+
|
11
|
+
ctl = new
|
12
|
+
|
13
|
+
if ctl.respond_to?(command)
|
14
|
+
ctl.send(command, args)
|
15
|
+
else
|
16
|
+
raise Racecar::Error, "invalid command: #{command}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def produce(args)
|
21
|
+
message = ProduceMessage.new
|
22
|
+
|
23
|
+
parser = OptionParser.new do |opts|
|
24
|
+
opts.banner = "Usage: racecarctl produce [options]"
|
25
|
+
|
26
|
+
opts.on("-v", "--value VALUE", "Set the message value") do |value|
|
27
|
+
message.value = value
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on("-k", "--key KEY", "Set the message key") do |key|
|
31
|
+
message.key = key
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on("-t", "--topic TOPIC", "Set the message topic") do |topic|
|
35
|
+
message.topic = topic
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
parser.parse!(args)
|
40
|
+
|
41
|
+
ConfigLoader.load!
|
42
|
+
|
43
|
+
Racecar.config.validate!
|
44
|
+
|
45
|
+
kafka = Kafka.new(
|
46
|
+
client_id: Racecar.config.client_id,
|
47
|
+
seed_brokers: Racecar.config.brokers,
|
48
|
+
logger: Racecar.logger,
|
49
|
+
connect_timeout: Racecar.config.connect_timeout,
|
50
|
+
socket_timeout: Racecar.config.socket_timeout,
|
51
|
+
)
|
52
|
+
|
53
|
+
kafka.deliver_message(message.value, key: message.key, topic: message.topic)
|
54
|
+
|
55
|
+
puts "=> Delivered message to Kafka cluster"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/racecar/runner.rb
CHANGED
@@ -29,10 +29,11 @@ module Racecar
|
|
29
29
|
trap("INT") { consumer.stop }
|
30
30
|
|
31
31
|
config.subscriptions.each do |subscription|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
consumer.subscribe(
|
33
|
+
subscription.topic,
|
34
|
+
start_from_beginning: subscription.start_from_beginning,
|
35
|
+
max_bytes_per_partition: subscription.max_bytes_per_partition,
|
36
|
+
)
|
36
37
|
end
|
37
38
|
|
38
39
|
begin
|
data/lib/racecar/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: racecar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Schierbeck
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-06
|
12
|
+
date: 2017-07-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ruby-kafka
|
@@ -73,6 +73,7 @@ email:
|
|
73
73
|
- bquorning@zendesk.com
|
74
74
|
executables:
|
75
75
|
- racecar
|
76
|
+
- racecarctl
|
76
77
|
extensions: []
|
77
78
|
extra_rdoc_files: []
|
78
79
|
files:
|
@@ -86,6 +87,7 @@ files:
|
|
86
87
|
- bin/setup
|
87
88
|
- examples/cat_consumer.rb
|
88
89
|
- exe/racecar
|
90
|
+
- exe/racecarctl
|
89
91
|
- lib/generators/racecar/consumer_generator.rb
|
90
92
|
- lib/generators/racecar/install_generator.rb
|
91
93
|
- lib/generators/templates/consumer.rb.erb
|
@@ -93,7 +95,9 @@ files:
|
|
93
95
|
- lib/racecar.rb
|
94
96
|
- lib/racecar/cli.rb
|
95
97
|
- lib/racecar/config.rb
|
98
|
+
- lib/racecar/config_loader.rb
|
96
99
|
- lib/racecar/consumer.rb
|
100
|
+
- lib/racecar/ctl.rb
|
97
101
|
- lib/racecar/env_loader.rb
|
98
102
|
- lib/racecar/runner.rb
|
99
103
|
- lib/racecar/version.rb
|