phobos_db_checkpoint 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5b5b26c404a1ef381a22acb11321da68ff796a07
4
- data.tar.gz: f70ffacba27f60a03be78c40caef88af565d61b0
3
+ metadata.gz: bf7c86a517c50d731d343b8cbf72f7fcacd413a4
4
+ data.tar.gz: ca87a4ce8ce804edcfdbc6cbc991404730bc8524
5
5
  SHA512:
6
- metadata.gz: e06985bb11ffc04fb94e00dcbedb158aa423643958e50cef89645e9dbf80c03bc7af391323c1483e32f9770deec18e27b1ba48a10fd1ac4537edcd4995c68a54
7
- data.tar.gz: f152ff0bc835ee77cb10f9ba5c238eaaef7d33abea0556ded954ed30ea65fe8fe54a727a4672aadf4084ac868c14866894c47ad541a4ba6a09633a1272bcebf5
6
+ metadata.gz: dab2ad650f6fe21d495ac3a6d2f8645907d17e39299c509c48f95f7f0005af4d88887b63b1a2a41f959f213626de8550159d6a8b1b14a04b043f7e0a95dfde0e
7
+ data.tar.gz: 6ac30e2f38f7d54e9ec1dd44266f113872deadd8f53aedfcded766a60096ce9aff0c7ef527aea866ba479f71dd697a8e96a762c7e9b72ab969574bc29bf903e0
data/.gitignore CHANGED
@@ -13,3 +13,5 @@ spec/examples.txt
13
13
  spec/setup/
14
14
  spec/tmp/
15
15
  .byebug_history
16
+ log/
17
+ spec/log/
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)
@@ -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
@@ -14,6 +14,14 @@ module PhobosDBCheckpoint
14
14
  save!
15
15
  end
16
16
 
17
+ def configured_handler
18
+ Phobos
19
+ .config
20
+ .listeners
21
+ .find { |listener| listener.group_id == self.group_id }
22
+ &.handler
23
+ end
24
+
17
25
  private
18
26
 
19
27
  def assign_checksum
@@ -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
@@ -1,3 +1,3 @@
1
1
  module PhobosDBCheckpoint
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  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
@@ -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.2.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-09-06 00:00:00.000000000 Z
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