phobos_db_checkpoint 0.2.0 → 0.3.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/.gitignore +2 -0
- data/CHANGELOG.md +7 -0
- data/README.md +41 -0
- data/lib/phobos_db_checkpoint.rb +7 -5
- data/lib/phobos_db_checkpoint/cli.rb +6 -0
- data/lib/phobos_db_checkpoint/event.rb +8 -0
- data/lib/phobos_db_checkpoint/events_api.rb +76 -0
- data/lib/phobos_db_checkpoint/middleware/database.rb +20 -0
- data/lib/phobos_db_checkpoint/middleware/logger.rb +68 -0
- data/lib/phobos_db_checkpoint/version.rb +1 -1
- data/phobos_db_checkpoint.gemspec +2 -0
- data/templates/config.ru +17 -0
- metadata +34 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf7c86a517c50d731d343b8cbf72f7fcacd413a4
|
4
|
+
data.tar.gz: ca87a4ce8ce804edcfdbc6cbc991404730bc8524
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dab2ad650f6fe21d495ac3a6d2f8645907d17e39299c509c48f95f7f0005af4d88887b63b1a2a41f959f213626de8550159d6a8b1b14a04b043f7e0a95dfde0e
|
7
|
+
data.tar.gz: 6ac30e2f38f7d54e9ec1dd44266f113872deadd8f53aedfcded766a60096ce9aff0c7ef527aea866ba479f71dd697a8e96a762c7e9b72ab969574bc29bf903e0
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -4,12 +4,19 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
6
6
|
|
7
|
+
## 0.3.0 (2016-10-10)
|
8
|
+
|
9
|
+
- [feature] Built-in sinatra APP with events API
|
10
|
+
|
7
11
|
## 0.2.0 (2016-09-06)
|
12
|
+
|
8
13
|
- [feature] New CLI command to generate migrations #6
|
9
14
|
- [feature] Automatically sets database pool size based on listeners max_concurrency #2
|
10
15
|
|
11
16
|
## 0.1.1 (2016-09-02)
|
17
|
+
|
12
18
|
- [bugfix] Handler is not injecting start and stop methods #4
|
13
19
|
|
14
20
|
## 0.1.0 (2016-08-29)
|
21
|
+
|
15
22
|
- Published on Github
|
data/README.md
CHANGED
@@ -15,6 +15,7 @@ Phobos DB Checkpoint is a plugin to [Phobos](https://github.com/klarna/phobos) a
|
|
15
15
|
1. [Setup](#setup)
|
16
16
|
1. [Handler](#handler)
|
17
17
|
1. [Accessing the events](#accessing-the-events)
|
18
|
+
1. [Events API](#events-api)
|
18
19
|
1. [Instrumentation](#instrumentation)
|
19
20
|
1. [Development](#development)
|
20
21
|
|
@@ -122,6 +123,46 @@ Note that the `PhobosDBCheckpoint::Handler` will automatically skip already hand
|
|
122
123
|
|
123
124
|
`PhobosDBCheckpoint::Event` is a plain `ActiveRecord::Base` model, feel free to play with it.
|
124
125
|
|
126
|
+
### <a name="events-api"></a> Events API
|
127
|
+
|
128
|
+
Phobos DB Checkpoint comes with a sinatra app which makes the event manipulation easy through its JSON API.
|
129
|
+
|
130
|
+
The __init_events_api__ command will generate a `config.ru` ready to use:
|
131
|
+
|
132
|
+
```sh
|
133
|
+
$ phobos_db_checkpoint init_events_api
|
134
|
+
create config.ru
|
135
|
+
Start the API with: `rackup config.ru`
|
136
|
+
```
|
137
|
+
|
138
|
+
```sh
|
139
|
+
$ curl "http://localhost:9292/v1/events/1"
|
140
|
+
# {
|
141
|
+
# "id": 1,
|
142
|
+
# "topic": "test-partitions",
|
143
|
+
# "group_id": "test-checkpoint-1",
|
144
|
+
# "entity_id": "1",
|
145
|
+
# "event_time": "2016-09-19T19:35:26.854Z",
|
146
|
+
# "event_type": "create",
|
147
|
+
# "event_version": "v1",
|
148
|
+
# "checksum": "188773471ec0f898fd81d272760a027f",
|
149
|
+
# "payload": "{\"a\":\"b\"}"
|
150
|
+
# }
|
151
|
+
```
|
152
|
+
|
153
|
+
The available routes are:
|
154
|
+
|
155
|
+
* GET `/ping`
|
156
|
+
* GET `/v1/events/:id`
|
157
|
+
* GET `/v1/events` This route accepts the following params:
|
158
|
+
* `limit`, default: 20
|
159
|
+
* `offset`, default: 0
|
160
|
+
* `entity_id`
|
161
|
+
* `topic`
|
162
|
+
* `group_id`
|
163
|
+
* `event_type`
|
164
|
+
* POST `/v1/events/:id/retry`
|
165
|
+
|
125
166
|
### <a name="instrumentation"></a> Instrumentation
|
126
167
|
|
127
168
|
Some operations are instrumented using [Phobos::Instrumentation](https://github.com/klarna/phobos#usage-instrumentation)
|
data/lib/phobos_db_checkpoint.rb
CHANGED
@@ -12,13 +12,14 @@ module PhobosDBCheckpoint
|
|
12
12
|
DEFAULT_DB_DIR = 'db'.freeze
|
13
13
|
DEFAULT_MIGRATION_PATH = File.join(DEFAULT_DB_DIR, 'migrate').freeze
|
14
14
|
DEFAULT_DB_CONFIG_PATH = 'config/database.yml'.freeze
|
15
|
+
DEFAULT_POOL_SIZE = 5.freeze
|
15
16
|
|
16
17
|
class << self
|
17
18
|
attr_reader :db_config
|
18
19
|
attr_accessor :db_config_path, :db_dir, :migration_path
|
19
20
|
|
20
|
-
def configure
|
21
|
-
load_db_config
|
21
|
+
def configure(pool_size: nil)
|
22
|
+
load_db_config(pool_size: pool_size)
|
22
23
|
at_exit { PhobosDBCheckpoint.close_db_connection }
|
23
24
|
ActiveRecord::Base.establish_connection(db_config)
|
24
25
|
end
|
@@ -27,15 +28,16 @@ module PhobosDBCheckpoint
|
|
27
28
|
ENV['RAILS_ENV'] ||= ENV['RACK_ENV'] ||= 'development'
|
28
29
|
end
|
29
30
|
|
30
|
-
def load_db_config
|
31
|
+
def load_db_config(pool_size: nil)
|
31
32
|
@db_config_path ||= DEFAULT_DB_CONFIG_PATH
|
32
33
|
configs = YAML.load_file(File.expand_path(@db_config_path))
|
33
34
|
@db_config = configs[env]
|
34
35
|
|
35
|
-
if Phobos.config
|
36
|
+
if pool_size.nil? && Phobos.config
|
36
37
|
pool_size = Phobos.config.listeners.map { |listener| listener.max_concurrency || 1 }.inject(&:+)
|
37
|
-
@db_config.merge!('pool' => pool_size)
|
38
38
|
end
|
39
|
+
|
40
|
+
@db_config.merge!('pool' => pool_size || DEFAULT_POOL_SIZE)
|
39
41
|
end
|
40
42
|
|
41
43
|
def close_db_connection
|
@@ -66,6 +66,12 @@ module PhobosDBCheckpoint
|
|
66
66
|
template(new_migration_template, destination_fullpath)
|
67
67
|
end
|
68
68
|
|
69
|
+
desc 'init-events-api', 'Initialize your project with events API'
|
70
|
+
def init_events_api
|
71
|
+
copy_file 'templates/config.ru', 'config.ru'
|
72
|
+
say ' Start the API with: `rackup config.ru`'
|
73
|
+
end
|
74
|
+
|
69
75
|
def self.source_root
|
70
76
|
File.expand_path(File.join(File.dirname(__FILE__), '../..'))
|
71
77
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'rack'
|
3
|
+
require 'sinatra/base'
|
4
|
+
|
5
|
+
require 'phobos_db_checkpoint/middleware/logger'
|
6
|
+
require 'phobos_db_checkpoint/middleware/database'
|
7
|
+
|
8
|
+
module PhobosDBCheckpoint
|
9
|
+
class EventsAPI < Sinatra::Base
|
10
|
+
VERSION = :v1
|
11
|
+
set :logging, nil
|
12
|
+
|
13
|
+
not_found do
|
14
|
+
content_type :json
|
15
|
+
{ error: true, message: 'not found' }.to_json
|
16
|
+
end
|
17
|
+
|
18
|
+
error ActiveRecord::RecordNotFound do
|
19
|
+
content_type :json
|
20
|
+
status 404
|
21
|
+
{ error: true, message: 'event not found' }.to_json
|
22
|
+
end
|
23
|
+
|
24
|
+
error StandardError do
|
25
|
+
content_type :json
|
26
|
+
error = env['sinatra.error']
|
27
|
+
{ error: true, message: error.message }.to_json
|
28
|
+
end
|
29
|
+
|
30
|
+
get '/ping' do
|
31
|
+
'PONG'
|
32
|
+
end
|
33
|
+
|
34
|
+
get "/#{VERSION}/events/:id" do
|
35
|
+
content_type :json
|
36
|
+
PhobosDBCheckpoint::Event
|
37
|
+
.find(params['id'])
|
38
|
+
.to_json
|
39
|
+
end
|
40
|
+
|
41
|
+
post "/#{VERSION}/events/:id/retry" do
|
42
|
+
content_type :json
|
43
|
+
event = PhobosDBCheckpoint::Event.find(params['id'])
|
44
|
+
handler_name = event.configured_handler
|
45
|
+
|
46
|
+
unless handler_name
|
47
|
+
status 422
|
48
|
+
return { error: true, message: 'no handler configured for this event' }.to_json
|
49
|
+
end
|
50
|
+
|
51
|
+
handler_class = handler_name.constantize
|
52
|
+
metadata = { listener_id: 'events_api/retry', group_id: event.group_id, topic: event.topic, retry_count: 0 }
|
53
|
+
event_action = handler_class.new.consume(event.payload, metadata)
|
54
|
+
|
55
|
+
{ acknowledged: event_action.is_a?(PhobosDBCheckpoint::Ack) }.to_json
|
56
|
+
end
|
57
|
+
|
58
|
+
get "/#{VERSION}/events" do
|
59
|
+
content_type :json
|
60
|
+
limit = (params['limit'] || 20).to_i
|
61
|
+
offset = (params['offset'] || 0).to_i
|
62
|
+
|
63
|
+
query = PhobosDBCheckpoint::Event
|
64
|
+
query = query.where(topic: params['topic']) if params['topic']
|
65
|
+
query = query.where(group_id: params['group_id']) if params['group_id']
|
66
|
+
query = query.where(entity_id: params['entity_id']) if params['entity_id']
|
67
|
+
query = query.where(event_type: params['event_type']) if params['event_type']
|
68
|
+
|
69
|
+
query
|
70
|
+
.order(event_time: :desc)
|
71
|
+
.limit(limit)
|
72
|
+
.offset(offset)
|
73
|
+
.to_json
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module PhobosDBCheckpoint
|
2
|
+
module Middleware
|
3
|
+
class Database
|
4
|
+
|
5
|
+
def initialize(app, options = {})
|
6
|
+
@app = app
|
7
|
+
pool_size = options.fetch(:pool_size, PhobosDBCheckpoint::DEFAULT_POOL_SIZE)
|
8
|
+
PhobosDBCheckpoint.configure(pool_size: pool_size)
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(request_env)
|
12
|
+
ActiveRecord::Base.connection_pool.with_connection do
|
13
|
+
@app.call(request_env)
|
14
|
+
end
|
15
|
+
ensure
|
16
|
+
ActiveRecord::Base.clear_active_connections!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module PhobosDBCheckpoint
|
4
|
+
module Middleware
|
5
|
+
class Logger
|
6
|
+
RACK_LOGGER = 'rack.logger'.freeze
|
7
|
+
SINATRA_ERROR = 'sinatra.error'.freeze
|
8
|
+
HTTP_VERSION = 'HTTP_VERSION'.freeze
|
9
|
+
PATH_INFO = 'PATH_INFO'.freeze
|
10
|
+
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
|
11
|
+
QUERY_STRING = 'QUERY_STRING'.freeze
|
12
|
+
CONTENT_LENGTH = 'Content-Length'.freeze
|
13
|
+
|
14
|
+
def initialize(app, options = {})
|
15
|
+
@app = app
|
16
|
+
Phobos.configure(options.fetch(:config, 'config/phobos.yml'))
|
17
|
+
Phobos.config.logger.file = options.fetch(:log_file, 'log/api.log')
|
18
|
+
Phobos.configure_logger
|
19
|
+
ActiveRecord::Base.logger = Phobos.logger
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(request_env)
|
23
|
+
began_at = Time.now
|
24
|
+
request_env[RACK_LOGGER] = Phobos.logger
|
25
|
+
status, header, body = @app.call(request_env)
|
26
|
+
header = Rack::Utils::HeaderHash.new(header)
|
27
|
+
body = Rack::BodyProxy.new(body) do
|
28
|
+
log(request_env, status, header, began_at)
|
29
|
+
end
|
30
|
+
[status, header, body]
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def log(request_env, status, header, began_at)
|
36
|
+
error = request_env[SINATRA_ERROR]
|
37
|
+
message = {
|
38
|
+
remote_address: request_env['HTTP_X_FORWARDED_FOR'] || request_env['REMOTE_ADDR'],
|
39
|
+
remote_user: request_env['REMOTE_USER'],
|
40
|
+
request_method: request_env[REQUEST_METHOD],
|
41
|
+
path: extract_path(request_env),
|
42
|
+
status: status.to_s[0..3],
|
43
|
+
content_length: extract_content_length(header),
|
44
|
+
request_time: "#{Time.now - began_at}s"
|
45
|
+
}
|
46
|
+
|
47
|
+
if error
|
48
|
+
Phobos.logger.error(message.merge(
|
49
|
+
exception_class: error.class.to_s,
|
50
|
+
exception_message: error.message,
|
51
|
+
backtrace: error.backtrace
|
52
|
+
))
|
53
|
+
else
|
54
|
+
Phobos.logger.info(message)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def extract_path(request_env)
|
59
|
+
"#{request_env[PATH_INFO]}#{request_env[QUERY_STRING].empty? ? "" : "?#{request_env[QUERY_STRING]}"} #{request_env[HTTP_VERSION]}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def extract_content_length(headers)
|
63
|
+
value = headers[CONTENT_LENGTH] or return
|
64
|
+
value.to_s == '0' ? nil : value
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -51,9 +51,11 @@ Gem::Specification.new do |spec|
|
|
51
51
|
spec.add_development_dependency 'pg'
|
52
52
|
spec.add_development_dependency 'database_cleaner'
|
53
53
|
spec.add_development_dependency 'rspec_junit_formatter', '0.2.2'
|
54
|
+
spec.add_development_dependency 'rack-test'
|
54
55
|
|
55
56
|
spec.add_dependency 'thor'
|
56
57
|
spec.add_dependency 'rake'
|
57
58
|
spec.add_dependency 'activerecord', '>= 4.0.0'
|
58
59
|
spec.add_dependency 'phobos', '>= 1.0.0'
|
60
|
+
spec.add_dependency 'sinatra'
|
59
61
|
end
|
data/templates/config.ru
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'phobos_db_checkpoint'
|
3
|
+
require 'phobos_db_checkpoint/events_api'
|
4
|
+
require_relative './phobos_boot.rb'
|
5
|
+
|
6
|
+
logger_config = {
|
7
|
+
# config: 'config/phobos.yml'
|
8
|
+
# log_file: 'log/api.log'
|
9
|
+
}
|
10
|
+
|
11
|
+
database_config = {
|
12
|
+
# pool_size: PhobosDBCheckpoint::DEFAULT_POOL_SIZE # 5
|
13
|
+
}
|
14
|
+
|
15
|
+
use PhobosDBCheckpoint::Middleware::Logger, logger_config
|
16
|
+
use PhobosDBCheckpoint::Middleware::Database, database_config
|
17
|
+
run PhobosDBCheckpoint::EventsAPI
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phobos_db_checkpoint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Túlio Ornelas
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2016-
|
16
|
+
date: 2016-10-10 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: bundler
|
@@ -141,6 +141,20 @@ dependencies:
|
|
141
141
|
- - '='
|
142
142
|
- !ruby/object:Gem::Version
|
143
143
|
version: 0.2.2
|
144
|
+
- !ruby/object:Gem::Dependency
|
145
|
+
name: rack-test
|
146
|
+
requirement: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
type: :development
|
152
|
+
prerelease: false
|
153
|
+
version_requirements: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
144
158
|
- !ruby/object:Gem::Dependency
|
145
159
|
name: thor
|
146
160
|
requirement: !ruby/object:Gem::Requirement
|
@@ -197,6 +211,20 @@ dependencies:
|
|
197
211
|
- - ">="
|
198
212
|
- !ruby/object:Gem::Version
|
199
213
|
version: 1.0.0
|
214
|
+
- !ruby/object:Gem::Dependency
|
215
|
+
name: sinatra
|
216
|
+
requirement: !ruby/object:Gem::Requirement
|
217
|
+
requirements:
|
218
|
+
- - ">="
|
219
|
+
- !ruby/object:Gem::Version
|
220
|
+
version: '0'
|
221
|
+
type: :runtime
|
222
|
+
prerelease: false
|
223
|
+
version_requirements: !ruby/object:Gem::Requirement
|
224
|
+
requirements:
|
225
|
+
- - ">="
|
226
|
+
- !ruby/object:Gem::Version
|
227
|
+
version: '0'
|
200
228
|
description: Phobos DB Checkpoint is a plugin to Phobos and is meant as a drop in
|
201
229
|
replacement to Phobos::Handler
|
202
230
|
email:
|
@@ -226,10 +254,14 @@ files:
|
|
226
254
|
- lib/phobos_db_checkpoint/cli.rb
|
227
255
|
- lib/phobos_db_checkpoint/event.rb
|
228
256
|
- lib/phobos_db_checkpoint/event_actions.rb
|
257
|
+
- lib/phobos_db_checkpoint/events_api.rb
|
229
258
|
- lib/phobos_db_checkpoint/handler.rb
|
259
|
+
- lib/phobos_db_checkpoint/middleware/database.rb
|
260
|
+
- lib/phobos_db_checkpoint/middleware/logger.rb
|
230
261
|
- lib/phobos_db_checkpoint/tasks.rb
|
231
262
|
- lib/phobos_db_checkpoint/version.rb
|
232
263
|
- phobos_db_checkpoint.gemspec
|
264
|
+
- templates/config.ru
|
233
265
|
- templates/database.yml.example
|
234
266
|
- templates/migrate/phobos_01_create_events.rb.erb
|
235
267
|
- templates/new_migration.rb.erb
|