deimos-ruby 1.4.0.pre.beta7 → 1.5.0.pre.beta2
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/.rubocop.yml +3 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile.lock +140 -58
- data/README.md +38 -11
- data/Rakefile +2 -2
- data/deimos-ruby.gemspec +3 -2
- data/docs/CONFIGURATION.md +1 -0
- data/docs/DATABASE_BACKEND.md +1 -1
- data/lib/deimos/active_record_consumer.rb +11 -12
- data/lib/deimos/active_record_producer.rb +2 -2
- data/lib/deimos/backends/base.rb +32 -0
- data/lib/deimos/backends/db.rb +6 -1
- data/lib/deimos/backends/kafka.rb +1 -1
- data/lib/deimos/backends/kafka_async.rb +1 -1
- data/lib/deimos/backends/test.rb +20 -0
- data/lib/deimos/base_consumer.rb +7 -7
- data/lib/deimos/batch_consumer.rb +0 -1
- data/lib/deimos/config/configuration.rb +4 -0
- data/lib/deimos/consumer.rb +0 -2
- data/lib/deimos/kafka_source.rb +1 -1
- data/lib/deimos/kafka_topic_info.rb +1 -1
- data/lib/deimos/message.rb +7 -7
- data/lib/deimos/producer.rb +10 -12
- data/lib/deimos/schema_backends/avro_base.rb +108 -0
- data/lib/deimos/schema_backends/avro_local.rb +30 -0
- data/lib/deimos/{schema_coercer.rb → schema_backends/avro_schema_coercer.rb} +39 -51
- data/lib/deimos/schema_backends/avro_schema_registry.rb +34 -0
- data/lib/deimos/schema_backends/avro_validation.rb +21 -0
- data/lib/deimos/schema_backends/base.rb +130 -0
- data/lib/deimos/schema_backends/mock.rb +42 -0
- data/lib/deimos/test_helpers.rb +42 -168
- data/lib/deimos/utils/db_producer.rb +5 -0
- data/lib/deimos/version.rb +1 -1
- data/lib/deimos.rb +22 -6
- data/lib/tasks/deimos.rake +1 -1
- data/spec/active_record_consumer_spec.rb +7 -0
- data/spec/{publish_backend_spec.rb → backends/base_spec.rb} +1 -1
- data/spec/backends/db_spec.rb +5 -0
- data/spec/batch_consumer_spec.rb +0 -8
- data/spec/config/configuration_spec.rb +20 -20
- data/spec/consumer_spec.rb +0 -1
- data/spec/deimos_spec.rb +0 -4
- data/spec/kafka_source_spec.rb +8 -0
- data/spec/producer_spec.rb +23 -37
- data/spec/rake_spec.rb +19 -0
- data/spec/schema_backends/avro_base_shared.rb +174 -0
- data/spec/schema_backends/avro_local_spec.rb +32 -0
- data/spec/schema_backends/avro_schema_registry_spec.rb +32 -0
- data/spec/schema_backends/avro_validation_spec.rb +24 -0
- data/spec/schema_backends/base_spec.rb +29 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/utils/db_producer_spec.rb +10 -0
- metadata +56 -33
- data/lib/deimos/avro_data_coder.rb +0 -89
- data/lib/deimos/avro_data_decoder.rb +0 -36
- data/lib/deimos/avro_data_encoder.rb +0 -51
- data/lib/deimos/monkey_patches/schema_store.rb +0 -19
- data/lib/deimos/publish_backend.rb +0 -30
- data/spec/avro_data_decoder_spec.rb +0 -18
- data/spec/avro_data_encoder_spec.rb +0 -37
- data/spec/updateable_schema_store_spec.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c2f20063d68540f1d48e8a87b210f42b146156120b0cc183bd9ce9b3aacee848
|
4
|
+
data.tar.gz: 23a7dac7a19d8defae93a5e675b614541d771b4c46746f12177dbd184ff37d67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3e9e905a67b22e953c9b8066d13adcff0f7c219676791f30e05ba34e007913c7615996278cf1aa52655a3f272d007baefd08f9d2612cbcc7d4453d656872197
|
7
|
+
data.tar.gz: 7978987a6ba5e56c2d9f5fd46582b17ed4ae85cac8b94fd67a65bac13dd60a0d56491eb91f060b030324e29f94b00158fdd0b87125ba4acd2b0ccfe887a009cf
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## UNRELEASED
|
9
9
|
|
10
|
+
# [1.5.0-beta2] - 2020-01-17
|
11
|
+
- Added schema backends, which should simplify Avro encoding and make it
|
12
|
+
more flexible for unit tests and local development.
|
13
|
+
- Add `:test` producer backend which replaces the existing TestHelpers
|
14
|
+
functionality of writing messages to an in-memory hash.
|
15
|
+
|
10
16
|
# [1.4.0-beta7] - 2019-12-16
|
11
17
|
- Clone loggers when assigning to multiple levels.
|
12
18
|
|
@@ -23,6 +29,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
23
29
|
# [1.4.0-beta1] - 2019-11-22
|
24
30
|
- Complete revamp of configuration method.
|
25
31
|
|
32
|
+
# [1.3.0-beta5] - 2020-01-14
|
33
|
+
- Added `db_producer.insert` and `db_producer.process` metrics.
|
34
|
+
|
35
|
+
# [1.3.0-beta4] - 2019-12-02
|
36
|
+
- Fixed bug where by running `rake deimos:start` without
|
37
|
+
specifying a producer backend would crash.
|
38
|
+
|
26
39
|
# [1.3.0-beta3] - 2019-11-26
|
27
40
|
- Fixed bug in TestHelpers where key_decoder was not stubbed out.
|
28
41
|
|
data/Gemfile.lock
CHANGED
@@ -1,51 +1,83 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
deimos-ruby (1.
|
5
|
-
|
6
|
-
avro_turf (~> 0.8)
|
4
|
+
deimos-ruby (1.5.0.pre.beta2)
|
5
|
+
avro_turf (~> 0.11)
|
7
6
|
phobos (~> 1.8.2.pre.beta2)
|
8
7
|
ruby-kafka (~> 0.7)
|
9
8
|
|
10
9
|
GEM
|
11
10
|
remote: https://rubygems.org/
|
12
11
|
specs:
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
actioncable (5.2.4)
|
13
|
+
actionpack (= 5.2.4)
|
14
|
+
nio4r (~> 2.0)
|
15
|
+
websocket-driver (>= 0.6.1)
|
16
|
+
actionmailer (5.2.4)
|
17
|
+
actionpack (= 5.2.4)
|
18
|
+
actionview (= 5.2.4)
|
19
|
+
activejob (= 5.2.4)
|
20
|
+
mail (~> 2.5, >= 2.5.4)
|
21
|
+
rails-dom-testing (~> 2.0)
|
22
|
+
actionpack (5.2.4)
|
23
|
+
actionview (= 5.2.4)
|
24
|
+
activesupport (= 5.2.4)
|
25
|
+
rack (~> 2.0)
|
26
|
+
rack-test (>= 0.6.3)
|
27
|
+
rails-dom-testing (~> 2.0)
|
28
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
29
|
+
actionview (5.2.4)
|
30
|
+
activesupport (= 5.2.4)
|
31
|
+
builder (~> 3.1)
|
32
|
+
erubi (~> 1.4)
|
33
|
+
rails-dom-testing (~> 2.0)
|
34
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
35
|
+
activejob (5.2.4)
|
36
|
+
activesupport (= 5.2.4)
|
37
|
+
globalid (>= 0.3.6)
|
38
|
+
activemodel (5.2.4)
|
39
|
+
activesupport (= 5.2.4)
|
40
|
+
activerecord (5.2.4)
|
41
|
+
activemodel (= 5.2.4)
|
42
|
+
activesupport (= 5.2.4)
|
18
43
|
arel (>= 9.0)
|
19
|
-
activerecord-import (0.
|
44
|
+
activerecord-import (1.0.3)
|
20
45
|
activerecord (>= 3.2)
|
21
|
-
|
46
|
+
activestorage (5.2.4)
|
47
|
+
actionpack (= 5.2.4)
|
48
|
+
activerecord (= 5.2.4)
|
49
|
+
marcel (~> 0.3.1)
|
50
|
+
activesupport (5.2.4)
|
22
51
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
23
52
|
i18n (>= 0.7, < 2)
|
24
53
|
minitest (~> 5.1)
|
25
54
|
tzinfo (~> 1.1)
|
26
55
|
arel (9.0.0)
|
27
56
|
ast (2.4.0)
|
28
|
-
avro (1.
|
57
|
+
avro (1.9.1)
|
29
58
|
multi_json
|
30
|
-
avro-patches (0.4.1)
|
31
|
-
avro (= 1.8.2)
|
32
59
|
avro_turf (0.11.0)
|
33
60
|
avro (>= 1.7.7, < 1.10)
|
34
61
|
excon (~> 0.45)
|
62
|
+
builder (3.2.4)
|
35
63
|
coderay (1.1.2)
|
36
|
-
concurrent-ruby (1.1.
|
37
|
-
concurrent-ruby-ext (1.1.
|
38
|
-
concurrent-ruby (= 1.1.
|
39
|
-
|
64
|
+
concurrent-ruby (1.1.5)
|
65
|
+
concurrent-ruby-ext (1.1.5)
|
66
|
+
concurrent-ruby (= 1.1.5)
|
67
|
+
crass (1.0.5)
|
68
|
+
ddtrace (0.30.0)
|
40
69
|
msgpack
|
41
70
|
diff-lcs (1.3)
|
42
71
|
digest-crc (0.4.1)
|
43
|
-
dogstatsd-ruby (4.
|
44
|
-
|
72
|
+
dogstatsd-ruby (4.5.0)
|
73
|
+
erubi (1.9.0)
|
74
|
+
excon (0.71.1)
|
45
75
|
exponential-backoff (0.0.4)
|
46
|
-
ffi (1.11.
|
76
|
+
ffi (1.11.3)
|
47
77
|
formatador (0.2.5)
|
48
|
-
|
78
|
+
globalid (0.4.2)
|
79
|
+
activesupport (>= 4.2.0)
|
80
|
+
guard (2.16.1)
|
49
81
|
formatador (>= 0.2.4)
|
50
82
|
listen (>= 2.7, < 4.0)
|
51
83
|
lumberjack (>= 1.0.12, < 2.0)
|
@@ -62,31 +94,43 @@ GEM
|
|
62
94
|
guard-rubocop (1.3.0)
|
63
95
|
guard (~> 2.0)
|
64
96
|
rubocop (~> 0.20)
|
65
|
-
i18n (1.
|
97
|
+
i18n (1.7.0)
|
66
98
|
concurrent-ruby (~> 1.0)
|
67
|
-
jaro_winkler (1.5.
|
68
|
-
listen (3.1
|
69
|
-
rb-fsevent (~> 0.
|
70
|
-
rb-inotify (~> 0.9, >= 0.9.
|
71
|
-
ruby_dep (~> 1.2)
|
99
|
+
jaro_winkler (1.5.4)
|
100
|
+
listen (3.2.1)
|
101
|
+
rb-fsevent (~> 0.10, >= 0.10.3)
|
102
|
+
rb-inotify (~> 0.9, >= 0.9.10)
|
72
103
|
little-plugger (1.1.4)
|
73
104
|
logging (2.2.2)
|
74
105
|
little-plugger (~> 1.1)
|
75
106
|
multi_json (~> 1.10)
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
107
|
+
loofah (2.4.0)
|
108
|
+
crass (~> 1.0.2)
|
109
|
+
nokogiri (>= 1.5.9)
|
110
|
+
lumberjack (1.0.13)
|
111
|
+
mail (2.7.1)
|
112
|
+
mini_mime (>= 0.1.1)
|
113
|
+
marcel (0.3.3)
|
114
|
+
mimemagic (~> 0.3.2)
|
115
|
+
method_source (0.9.2)
|
116
|
+
mimemagic (0.3.3)
|
117
|
+
mini_mime (1.0.2)
|
118
|
+
mini_portile2 (2.4.0)
|
119
|
+
minitest (5.13.0)
|
120
|
+
msgpack (1.3.1)
|
80
121
|
multi_json (1.14.1)
|
81
|
-
mysql2 (0.5.
|
122
|
+
mysql2 (0.5.3)
|
82
123
|
nenv (0.3.0)
|
83
|
-
|
124
|
+
nio4r (2.5.2)
|
125
|
+
nokogiri (1.10.7)
|
126
|
+
mini_portile2 (~> 2.4.0)
|
127
|
+
notiffany (0.1.3)
|
84
128
|
nenv (~> 0.1)
|
85
129
|
shellany (~> 0.0)
|
86
|
-
parallel (1.
|
87
|
-
parser (2.6.
|
130
|
+
parallel (1.19.1)
|
131
|
+
parser (2.6.5.0)
|
88
132
|
ast (~> 2.4.0)
|
89
|
-
pg (1.1.
|
133
|
+
pg (1.1.4)
|
90
134
|
phobos (1.8.2)
|
91
135
|
activesupport (>= 3.0.0)
|
92
136
|
concurrent-ruby (>= 1.0.2)
|
@@ -95,49 +139,85 @@ GEM
|
|
95
139
|
logging
|
96
140
|
ruby-kafka
|
97
141
|
thor
|
98
|
-
pry (0.
|
142
|
+
pry (0.12.2)
|
99
143
|
coderay (~> 1.1.0)
|
100
144
|
method_source (~> 0.9.0)
|
145
|
+
rack (2.0.8)
|
146
|
+
rack-test (1.1.0)
|
147
|
+
rack (>= 1.0, < 3)
|
148
|
+
rails (5.2.4)
|
149
|
+
actioncable (= 5.2.4)
|
150
|
+
actionmailer (= 5.2.4)
|
151
|
+
actionpack (= 5.2.4)
|
152
|
+
actionview (= 5.2.4)
|
153
|
+
activejob (= 5.2.4)
|
154
|
+
activemodel (= 5.2.4)
|
155
|
+
activerecord (= 5.2.4)
|
156
|
+
activestorage (= 5.2.4)
|
157
|
+
activesupport (= 5.2.4)
|
158
|
+
bundler (>= 1.3.0)
|
159
|
+
railties (= 5.2.4)
|
160
|
+
sprockets-rails (>= 2.0.0)
|
161
|
+
rails-dom-testing (2.0.3)
|
162
|
+
activesupport (>= 4.2.0)
|
163
|
+
nokogiri (>= 1.6)
|
164
|
+
rails-html-sanitizer (1.3.0)
|
165
|
+
loofah (~> 2.3)
|
166
|
+
railties (5.2.4)
|
167
|
+
actionpack (= 5.2.4)
|
168
|
+
activesupport (= 5.2.4)
|
169
|
+
method_source
|
170
|
+
rake (>= 0.8.7)
|
171
|
+
thor (>= 0.19.0, < 2.0)
|
101
172
|
rainbow (3.0.0)
|
102
173
|
rake (10.5.0)
|
103
|
-
rb-fsevent (0.10.
|
104
|
-
rb-inotify (0.
|
105
|
-
ffi (
|
106
|
-
rspec (3.
|
107
|
-
rspec-core (~> 3.
|
108
|
-
rspec-expectations (~> 3.
|
109
|
-
rspec-mocks (~> 3.
|
110
|
-
rspec-core (3.
|
111
|
-
rspec-support (~> 3.
|
112
|
-
rspec-expectations (3.
|
174
|
+
rb-fsevent (0.10.3)
|
175
|
+
rb-inotify (0.10.0)
|
176
|
+
ffi (~> 1.0)
|
177
|
+
rspec (3.9.0)
|
178
|
+
rspec-core (~> 3.9.0)
|
179
|
+
rspec-expectations (~> 3.9.0)
|
180
|
+
rspec-mocks (~> 3.9.0)
|
181
|
+
rspec-core (3.9.0)
|
182
|
+
rspec-support (~> 3.9.0)
|
183
|
+
rspec-expectations (3.9.0)
|
113
184
|
diff-lcs (>= 1.2.0, < 2.0)
|
114
|
-
rspec-support (~> 3.
|
115
|
-
rspec-mocks (3.
|
185
|
+
rspec-support (~> 3.9.0)
|
186
|
+
rspec-mocks (3.9.0)
|
116
187
|
diff-lcs (>= 1.2.0, < 2.0)
|
117
|
-
rspec-support (~> 3.
|
118
|
-
rspec-support (3.
|
119
|
-
rspec_junit_formatter (0.
|
188
|
+
rspec-support (~> 3.9.0)
|
189
|
+
rspec-support (3.9.0)
|
190
|
+
rspec_junit_formatter (0.4.1)
|
120
191
|
rspec-core (>= 2, < 4, != 2.12.0)
|
121
|
-
rubocop (0.
|
192
|
+
rubocop (0.77.0)
|
122
193
|
jaro_winkler (~> 1.5.1)
|
123
194
|
parallel (~> 1.10)
|
124
195
|
parser (>= 2.6)
|
125
196
|
rainbow (>= 2.2.2, < 4.0)
|
126
197
|
ruby-progressbar (~> 1.7)
|
127
198
|
unicode-display_width (>= 1.4.0, < 1.7)
|
128
|
-
rubocop-rspec (1.
|
129
|
-
rubocop (>= 0.
|
199
|
+
rubocop-rspec (1.37.1)
|
200
|
+
rubocop (>= 0.68.1)
|
130
201
|
ruby-kafka (0.7.10)
|
131
202
|
digest-crc
|
132
203
|
ruby-progressbar (1.10.1)
|
133
|
-
ruby_dep (1.5.0)
|
134
204
|
shellany (0.0.1)
|
135
|
-
|
136
|
-
|
205
|
+
sprockets (4.0.0)
|
206
|
+
concurrent-ruby (~> 1.0)
|
207
|
+
rack (> 1, < 3)
|
208
|
+
sprockets-rails (3.2.1)
|
209
|
+
actionpack (>= 4.0)
|
210
|
+
activesupport (>= 4.0)
|
211
|
+
sprockets (>= 3.0.0)
|
212
|
+
sqlite3 (1.4.1)
|
213
|
+
thor (1.0.1)
|
137
214
|
thread_safe (0.3.6)
|
138
215
|
tzinfo (1.2.5)
|
139
216
|
thread_safe (~> 0.1)
|
140
217
|
unicode-display_width (1.6.0)
|
218
|
+
websocket-driver (0.7.1)
|
219
|
+
websocket-extensions (>= 0.1.0)
|
220
|
+
websocket-extensions (0.1.4)
|
141
221
|
|
142
222
|
PLATFORMS
|
143
223
|
ruby
|
@@ -145,6 +225,7 @@ PLATFORMS
|
|
145
225
|
DEPENDENCIES
|
146
226
|
activerecord (~> 5.2)
|
147
227
|
activerecord-import
|
228
|
+
avro (~> 1.9)
|
148
229
|
bundler (~> 1)
|
149
230
|
ddtrace (~> 0.11)
|
150
231
|
deimos-ruby!
|
@@ -154,6 +235,7 @@ DEPENDENCIES
|
|
154
235
|
guard-rubocop (~> 1)
|
155
236
|
mysql2 (~> 0.5)
|
156
237
|
pg (~> 1.1)
|
238
|
+
rails (~> 5.2)
|
157
239
|
rake (~> 10)
|
158
240
|
rspec (~> 3)
|
159
241
|
rspec_junit_formatter (~> 0.3)
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
<img src="https://img.shields.io/codeclimate/maintainability/flipp-oss/deimos.svg"/>
|
7
7
|
</p>
|
8
8
|
|
9
|
-
A Ruby framework for marrying Kafka, Avro, and/or ActiveRecord and provide
|
9
|
+
A Ruby framework for marrying Kafka, a schema definition like Avro, and/or ActiveRecord and provide
|
10
10
|
a useful toolbox of goodies for Ruby-based Kafka development.
|
11
11
|
Built on Phobos and hence Ruby-Kafka.
|
12
12
|
|
@@ -14,6 +14,7 @@ Built on Phobos and hence Ruby-Kafka.
|
|
14
14
|
* [Installation](#installation)
|
15
15
|
* [Versioning](#versioning)
|
16
16
|
* [Configuration](#configuration)
|
17
|
+
* [Schemas](#schemas)
|
17
18
|
* [Producers](#producers)
|
18
19
|
* [Auto-added Fields](#auto-added-fields)
|
19
20
|
* [Coerced Values](#coerced-values)
|
@@ -60,6 +61,27 @@ gem 'deimos-ruby', '~> 1.1'
|
|
60
61
|
|
61
62
|
For a full configuration reference, please see [the configuration docs ](docs/CONFIGURATION.md).
|
62
63
|
|
64
|
+
# Schemas
|
65
|
+
|
66
|
+
Deimos was originally written only supporting Avro encoding via a schema registry.
|
67
|
+
This has since been expanded to a plugin architecture allowing messages to be
|
68
|
+
encoded and decoded via any schema specification you wish.
|
69
|
+
|
70
|
+
Currently we have the following possible schema backends:
|
71
|
+
* Avro Local (use pure Avro)
|
72
|
+
* Avro Schema Registry (use the Confluent Schema Registry)
|
73
|
+
* Avro Validation (validate using an Avro schema but leave decoded - this is useful
|
74
|
+
for unit testing and development)
|
75
|
+
* Mock (no actual encoding/decoding).
|
76
|
+
|
77
|
+
Note that to use Avro-encoding, you must include the [avro_turf](https://github.com/dasch/avro_turf) gem in your
|
78
|
+
Gemfile.
|
79
|
+
|
80
|
+
Other possible schemas could include [Protobuf](https://developers.google.com/protocol-buffers), [JSONSchema](https://json-schema.org/), etc. Feel free to
|
81
|
+
contribute!
|
82
|
+
|
83
|
+
To create a new schema backend, please see the existing examples [here](lib/deimos/schema_backends).
|
84
|
+
|
63
85
|
# Producers
|
64
86
|
|
65
87
|
Producers will look like this:
|
@@ -137,7 +159,7 @@ produced by Phobos and RubyKafka):
|
|
137
159
|
* topic
|
138
160
|
* exception_object
|
139
161
|
* payloads - the unencoded payloads
|
140
|
-
* `encode_messages` - sent when messages are being
|
162
|
+
* `encode_messages` - sent when messages are being schema-encoded.
|
141
163
|
* producer - the class that produced the message
|
142
164
|
* topic
|
143
165
|
* payloads - the unencoded payloads
|
@@ -165,8 +187,8 @@ Similarly:
|
|
165
187
|
### Kafka Message Keys
|
166
188
|
|
167
189
|
Topics representing events rather than domain data don't need keys. However,
|
168
|
-
best practice for domain messages is to
|
169
|
-
with a separate
|
190
|
+
best practice for domain messages is to schema-encode message keys
|
191
|
+
with a separate schema.
|
170
192
|
|
171
193
|
This enforced by requiring producers to define a `key_config` directive. If
|
172
194
|
any message comes in with a key, the producer will error out if `key_config` is
|
@@ -179,7 +201,7 @@ There are three possible configurations to use:
|
|
179
201
|
all your messages in a topic need to have a key, or they all need to have
|
180
202
|
no key. This is a good choice for events that aren't keyed - you can still
|
181
203
|
set a partition key.
|
182
|
-
* `key_config plain: true` - this indicates that you are not using an
|
204
|
+
* `key_config plain: true` - this indicates that you are not using an encoded
|
183
205
|
key. Use this for legacy topics - new topics should not use this setting.
|
184
206
|
* `key_config schema: 'MyKeySchema-key'` - this tells the producer to look for
|
185
207
|
an existing key schema named `MyKeySchema-key` in the schema registry and to
|
@@ -234,8 +256,8 @@ like this:
|
|
234
256
|
```
|
235
257
|
|
236
258
|
If you publish a payload `{ "test_id" => "123", "some_int" => 123 }`, this
|
237
|
-
will be turned into a key that looks like `{ "test_id" => "123"}` and encoded
|
238
|
-
|
259
|
+
will be turned into a key that looks like `{ "test_id" => "123"}` and schema-encoded
|
260
|
+
before being sent to Kafka.
|
239
261
|
|
240
262
|
If you are using `plain` or `schema` as your config, you will need to have a
|
241
263
|
special `payload_key` key to your payload hash. This will be extracted and
|
@@ -261,7 +283,7 @@ class MyConsumer < Deimos::Consumer
|
|
261
283
|
|
262
284
|
def consume(payload, metadata)
|
263
285
|
# Same method as Phobos consumers.
|
264
|
-
# payload is an
|
286
|
+
# payload is an schema-decoded hash.
|
265
287
|
# metadata is a hash that contains information like :key and :topic.
|
266
288
|
# In general, your key should be included in the payload itself. However,
|
267
289
|
# if you need to access it separately from the payload, you can use
|
@@ -311,7 +333,7 @@ this sample:
|
|
311
333
|
class MyBatchConsumer < Deimos::BatchConsumer
|
312
334
|
|
313
335
|
def consume_batch(payloads, metadata)
|
314
|
-
# payloads is an array of
|
336
|
+
# payloads is an array of schema-decoded hashes.
|
315
337
|
# metadata is a hash that contains information like :keys and :topic.
|
316
338
|
# Keys are automatically decoded and available as an array with
|
317
339
|
# the same cardinality as the payloads. If you need to iterate
|
@@ -581,6 +603,11 @@ The following metrics are reported:
|
|
581
603
|
with the database backend. Tagged with the topic that is waiting.
|
582
604
|
Will send a value of 0 with no topics tagged if there are no messages
|
583
605
|
waiting.
|
606
|
+
* `db_producer.insert` - the number of messages inserted into the database
|
607
|
+
for publishing. Tagged with `topic:{topic_name}`
|
608
|
+
* `db_producer.process` - the number of DB messages processed. Note that this
|
609
|
+
is *not* the same as the number of messages *published* if those messages
|
610
|
+
are compacted. Tagged with `topic:{topic_name}`
|
584
611
|
|
585
612
|
### Configuring Metrics Providers
|
586
613
|
|
@@ -604,7 +631,7 @@ Also see [deimos.rb](lib/deimos.rb) under `Configure metrics` to see how the met
|
|
604
631
|
Deimos also includes some tracing for kafka consumers. It ships with
|
605
632
|
DataDog support, but you can add custom tracing providers as well.
|
606
633
|
|
607
|
-
Trace spans are used for when incoming messages are
|
634
|
+
Trace spans are used for when incoming messages are schema-decoded, and a
|
608
635
|
separate span for message consume logic.
|
609
636
|
|
610
637
|
### Configuring Tracing Providers
|
@@ -749,7 +776,7 @@ be
|
|
749
776
|
}
|
750
777
|
```
|
751
778
|
|
752
|
-
Both payload and key will be
|
779
|
+
Both payload and key will be schema-decoded as necessary according to the
|
753
780
|
key config.
|
754
781
|
|
755
782
|
You can also just pass an existing producer or consumer class into the method,
|
data/Rakefile
CHANGED
@@ -6,8 +6,8 @@ begin
|
|
6
6
|
|
7
7
|
RSpec::Core::RakeTask.new(:spec)
|
8
8
|
task(default: :spec)
|
9
|
-
rescue LoadError # rubocop:disable Lint/
|
9
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
10
10
|
# no rspec available
|
11
11
|
end
|
12
12
|
|
13
|
-
import('./lib/tasks/
|
13
|
+
import('./lib/tasks/deimos.rake')
|
data/deimos-ruby.gemspec
CHANGED
@@ -18,13 +18,13 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_runtime_dependency('
|
22
|
-
spec.add_runtime_dependency('avro_turf', '~> 0.8')
|
21
|
+
spec.add_runtime_dependency('avro_turf', '~> 0.11')
|
23
22
|
spec.add_runtime_dependency('phobos', '~> 1.8.2.pre.beta2')
|
24
23
|
spec.add_runtime_dependency('ruby-kafka', '~> 0.7')
|
25
24
|
|
26
25
|
spec.add_development_dependency('activerecord', '~> 5.2')
|
27
26
|
spec.add_development_dependency('activerecord-import')
|
27
|
+
spec.add_development_dependency('avro', '~> 1.9')
|
28
28
|
spec.add_development_dependency('bundler', '~> 1')
|
29
29
|
spec.add_development_dependency('ddtrace', '~> 0.11')
|
30
30
|
spec.add_development_dependency('dogstatsd-ruby', '~> 4.2')
|
@@ -33,6 +33,7 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_development_dependency('guard-rubocop', '~> 1')
|
34
34
|
spec.add_development_dependency('mysql2', '~> 0.5')
|
35
35
|
spec.add_development_dependency('pg', '~> 1.1')
|
36
|
+
spec.add_development_dependency('rails', '~> 5.2')
|
36
37
|
spec.add_development_dependency('rake', '~> 10')
|
37
38
|
spec.add_development_dependency('rspec', '~> 3')
|
38
39
|
spec.add_development_dependency('rspec_junit_formatter', '~>0.3')
|
data/docs/CONFIGURATION.md
CHANGED
@@ -144,6 +144,7 @@ producers.backend|`:kafka_async`|Currently can be set to `:db`, `:kafka`, or `:k
|
|
144
144
|
|
145
145
|
Config name|Default|Description
|
146
146
|
-----------|-------|-----------
|
147
|
+
schema.backend|`:mock`|Backend representing the schema encoder/decoder. You can see a full list [here](../lib/deimos/schema_backends).
|
147
148
|
schema.registry_url|`http://localhost:8081`|URL of the Confluent schema registry.
|
148
149
|
schema.path|nil|Local path to find your schemas.
|
149
150
|
|
data/docs/DATABASE_BACKEND.md
CHANGED
@@ -77,7 +77,7 @@ The database backend consists of three tables:
|
|
77
77
|
|
78
78
|
* `kafka_messages` - this keeps track of the messages that were "published",
|
79
79
|
including the payload, topic, key and partition key. These messages
|
80
|
-
are *raw data* - all processing, including
|
80
|
+
are *raw data* - all processing, including schema-encoding, must happen
|
81
81
|
upstream before they are inserted.
|
82
82
|
* `kafka_topic_info` - this table is essentially a lock table used to ensure
|
83
83
|
that only one producer thread is ever "working" on a topic at a time.
|
@@ -68,32 +68,31 @@ module Deimos
|
|
68
68
|
def record_attributes(payload)
|
69
69
|
klass = self.class.config[:record_class]
|
70
70
|
attributes = {}
|
71
|
-
|
72
|
-
schema.fields.each do |field|
|
71
|
+
self.class.decoder.schema_fields.each do |field|
|
73
72
|
column = klass.columns.find { |c| c.name == field.name }
|
74
73
|
next if column.nil?
|
75
74
|
next if %w(updated_at created_at).include?(field.name)
|
76
75
|
|
77
|
-
attributes[field.name] = _coerce_field(
|
76
|
+
attributes[field.name] = _coerce_field(column, payload[field.name])
|
78
77
|
end
|
79
78
|
attributes
|
80
79
|
end
|
81
80
|
|
82
81
|
private
|
83
82
|
|
84
|
-
# @param field [Avro::Schema]
|
85
83
|
# @param column [ActiveRecord::ConnectionAdapters::Column]
|
86
84
|
# @param val [Object]
|
87
|
-
def _coerce_field(
|
85
|
+
def _coerce_field(column, val)
|
88
86
|
return nil if val.nil?
|
89
87
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
88
|
+
if column.type == :datetime
|
89
|
+
int_val = begin
|
90
|
+
val.is_a?(Integer) ? val : (val.is_a?(String) && Integer(val))
|
91
|
+
rescue StandardError
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
return Time.zone.at(int_val) if int_val
|
97
96
|
end
|
98
97
|
|
99
98
|
val
|
@@ -53,10 +53,10 @@ module Deimos
|
|
53
53
|
# is not set.
|
54
54
|
# @return [Hash]
|
55
55
|
def generate_payload(attributes, _record)
|
56
|
-
|
56
|
+
fields = self.encoder.schema_fields
|
57
57
|
payload = attributes.stringify_keys
|
58
58
|
payload.delete_if do |k, _|
|
59
|
-
k.to_sym != :payload_key && !
|
59
|
+
k.to_sym != :payload_key && !fields.map(&:name).include?(k)
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deimos
|
4
|
+
module Backends
|
5
|
+
# Abstract class for all publish backends.
|
6
|
+
class Base
|
7
|
+
class << self
|
8
|
+
# @param producer_class [Class < Deimos::Producer]
|
9
|
+
# @param messages [Array<Deimos::Message>]
|
10
|
+
def publish(producer_class:, messages:)
|
11
|
+
Deimos.config.logger.info(
|
12
|
+
message: 'Publishing messages',
|
13
|
+
topic: producer_class.topic,
|
14
|
+
payloads: messages.map do |message|
|
15
|
+
{
|
16
|
+
payload: message.payload,
|
17
|
+
key: message.key
|
18
|
+
}
|
19
|
+
end
|
20
|
+
)
|
21
|
+
execute(producer_class: producer_class, messages: messages)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param producer_class [Class < Deimos::Producer]
|
25
|
+
# @param messages [Array<Deimos::Message>]
|
26
|
+
def execute(producer_class:, messages:)
|
27
|
+
raise NotImplementedError
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/deimos/backends/db.rb
CHANGED
@@ -6,7 +6,7 @@ module Deimos
|
|
6
6
|
module Backends
|
7
7
|
# Backend which saves messages to the database instead of immediately
|
8
8
|
# sending them.
|
9
|
-
class Db <
|
9
|
+
class Db < Base
|
10
10
|
class << self
|
11
11
|
# :nodoc:
|
12
12
|
def execute(producer_class:, messages:)
|
@@ -20,6 +20,11 @@ module Deimos
|
|
20
20
|
message
|
21
21
|
end
|
22
22
|
Deimos::KafkaMessage.import(records)
|
23
|
+
Deimos.config.metrics&.increment(
|
24
|
+
'db_producer.insert',
|
25
|
+
tags: %W(topic:#{producer_class.topic}),
|
26
|
+
by: records.size
|
27
|
+
)
|
23
28
|
end
|
24
29
|
end
|
25
30
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deimos
|
4
|
+
module Backends
|
5
|
+
# Backend which saves messages to an in-memory hash.
|
6
|
+
class Test < Deimos::Backends::Base
|
7
|
+
class << self
|
8
|
+
# @return [Array<Hash>]
|
9
|
+
def sent_messages
|
10
|
+
@sent_messages ||= []
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# @override
|
15
|
+
def self.execute(producer_class:, messages:)
|
16
|
+
self.sent_messages.concat(messages.map(&:to_h))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|