startback 0.8.3 → 0.10.1

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
  SHA256:
3
- metadata.gz: 25d875283dd978829a7a55cc1a92bb75ba6e00ea77119e176e1537b326b40793
4
- data.tar.gz: 79ec3c424a831f4c596606bc5b5f08a500352b9d776198496ae65d5a02c867f1
3
+ metadata.gz: ecd3fca505de294b037fbb0f7e15e9e5242823751169a8b745cd5717b9098945
4
+ data.tar.gz: d0b1546710de2899a9ea246b66a03661f58eea3ec03ba7d4f3c8e95c52d49245
5
5
  SHA512:
6
- metadata.gz: fd9b8f38650403793f642fad572ce7137b546c312294530a2b962693b855884009339d21e61316f647e85e95d000460b54dd02d6f83f4684bcfda1a44c65f934
7
- data.tar.gz: 1cda02569aaccac6cab2c6e612d8ef99c814c5c8a51cf082bb9f589d1ac51f3db7cbca86bb616e0f45fbc78fb34e23678abdc4dc2c0b7f4080b6ac18466dddd8
6
+ metadata.gz: b0e1bde2cb31f15eeb777da14a9d22062f7dab45028d9de171c9de12526a4571296591eb208c4ebd6c1059730ef671ca76fea98553e7d618272244c2d4f8b7d3
7
+ data.tar.gz: 47a40ac9677ea5998c8089d6b5ca01b7ef7144810ecdde1163e6286fe41313d8009b723f52c074408aec6c316cacb978a6cfe9179f068ff4fe462e7647b75f8e
@@ -74,13 +74,13 @@ module Startback
74
74
 
75
75
  protected
76
76
 
77
- def op_to_trail(op, time, ex = nil)
77
+ def op_to_trail(op, time = nil, ex = nil)
78
78
  log_msg = {
79
79
  op_took: time ? time.round(8) : nil,
80
80
  op: op_name(op),
81
81
  context: op_context(op),
82
82
  op_data: op_data(op)
83
- }
83
+ }.compact
84
84
  log_msg[:error] = ex if ex
85
85
  log_msg
86
86
  end
@@ -104,6 +104,8 @@ module Startback
104
104
  op.input
105
105
  elsif op.respond_to?(:request, false)
106
106
  op.request
107
+ elsif op.is_a?(Operation::MultiOperation)
108
+ op.ops.map{ |sub_op| op_to_trail(sub_op) }
107
109
  end
108
110
  sanitize(data)
109
111
  end
@@ -35,6 +35,8 @@ module Startback
35
35
  class Async
36
36
  include Support::Robustness
37
37
 
38
+ CHANNEL_KEY = 'Startback::Bus::Bunny::Async::ChannelKey'
39
+
38
40
  DEFAULT_OPTIONS = {
39
41
  # (optional) The URL to use for connecting to RabbitMQ.
40
42
  url: ENV['STARTBACK_BUS_BUNNY_ASYNC_URL'],
@@ -65,11 +67,15 @@ module Startback
65
67
  try_max_times(10) do
66
68
  @bunny = ::Bunny.new(conn)
67
69
  @bunny.start
68
- @channel = @bunny.create_channel
70
+ channel
69
71
  log(:info, {op: "#{self.class.name}#connect", op_data: conn}, options[:context])
70
72
  end
71
73
  end
72
- attr_reader :channel, :options
74
+ attr_reader :options
75
+
76
+ def channel
77
+ Thread.current[CHANNEL_KEY] ||= @bunny.create_channel
78
+ end
73
79
 
74
80
  def emit(event)
75
81
  stop_errors(self, "emit", event.context) do
@@ -2,8 +2,13 @@ module Startback
2
2
  module Errors
3
3
 
4
4
  class Error < StandardError
5
- class << self
5
+ def initialize(message = nil, causes = nil)
6
+ super(message)
7
+ @causes = Array(causes)
8
+ end
9
+ attr_reader :causes
6
10
 
11
+ class << self
7
12
  def status(code = nil)
8
13
  if code.nil?
9
14
  @code || (superclass.respond_to?(:status) ? superclass.status : 500)
@@ -22,11 +27,19 @@ module Startback
22
27
  msg = super
23
28
  return msg unless msg == self.class.name
24
29
  parts = self.class.name.split('::').last.gsub(/[A-Z]/){|x|
25
- " #{x.downcase}"
30
+ " #{x.downcase}"
26
31
  }.strip.split(" ")
27
32
  parts = parts[0...-1] unless self.class.keep_error
28
33
  parts.join(" ").capitalize
29
34
  end
35
+
36
+ def has_causes?
37
+ causes && !causes.empty?
38
+ end
39
+
40
+ def cause
41
+ causes&.first
42
+ end
30
43
  end
31
44
 
32
45
  class BadRequestError < Error
@@ -1,6 +1,6 @@
1
1
  module Startback
2
2
  class Operation
3
- class MultiOperation
3
+ class MultiOperation < Operation
4
4
 
5
5
  def initialize(ops = [])
6
6
  @ops = ops
@@ -29,6 +29,7 @@ module Startback
29
29
  # end
30
30
  #
31
31
  class Operation
32
+ extend Support::TransactionPolicy
32
33
  include Errors
33
34
  include Support::OperationRunner
34
35
  include Support::Hooks.new(:call)
@@ -3,14 +3,28 @@ module Startback
3
3
  class LogFormatter
4
4
 
5
5
  def call(severity, time, progname, msg)
6
- if msg[:error] && msg[:error].respond_to?(:message, true)
7
- msg[:backtrace] = msg[:error].backtrace[0..25] if severity == "FATAL"
8
- msg[:error] = msg[:error].message
9
- end
10
6
  {
11
7
  severity: severity,
12
- time: time,
13
- }.merge(msg).to_json << "\n"
8
+ time: time
9
+ }.merge(msg)
10
+ .merge(error: error_to_json(msg[:error], severity))
11
+ .compact
12
+ .to_json << "\n"
13
+ end
14
+
15
+ def error_to_json(error, severity = nil)
16
+ return error if error.nil?
17
+ return error if error.is_a?(String)
18
+ return error.to_s unless error.is_a?(Exception)
19
+
20
+ backtrace = error.backtrace[0..25] if severity == "FATAL"
21
+ causes = error.causes.map{|c| error_to_json(c) } if error.respond_to?(:causes)
22
+ causes = nil if causes && causes.empty?
23
+ {
24
+ message: error.message,
25
+ backtrace: backtrace,
26
+ causes: causes
27
+ }.compact
14
28
  end
15
29
 
16
30
  end # class LogFormatter
@@ -0,0 +1,25 @@
1
+ module Startback
2
+ module Support
3
+ class TransactionManager
4
+
5
+ def initialize(db, method = :transaction)
6
+ @db = db
7
+ @method = method
8
+ end
9
+
10
+ def call(runner, op, &then_block)
11
+ raise ArgumentError, "A block is required" unless then_block
12
+
13
+ before = (op.class.transaction_policy == :before_call)
14
+ if before
15
+ @db.send(@method) do
16
+ then_block.call
17
+ end
18
+ else
19
+ then_block.call
20
+ end
21
+ end
22
+
23
+ end # class TransactionManager
24
+ end # module Support
25
+ end # module Startback
@@ -0,0 +1,33 @@
1
+ module Startback
2
+ module Support
3
+ module TransactionPolicy
4
+
5
+ # Returns the operation's transaction policy
6
+ def transaction_policy
7
+ @transaction_policy || :before_call
8
+ end
9
+
10
+ # Sets the transaction policy to use. Valid values are:
11
+ # - before_call : the transaction is started by the operation
12
+ # runner, right before calling the #call method on operation
13
+ # instance
14
+ # - within_call: the transaction is started by the operation
15
+ # itself, as part of its internal logic.
16
+ def transaction_policy=(policy)
17
+ unless [:before_call, :within_call].include?(policy)
18
+ raise ArgumentError, "Unknown policy `#{policy}`"
19
+ end
20
+ @transaction_policy = policy
21
+ end
22
+
23
+ def after_commit(&bl)
24
+ after_call do
25
+ db.after_commit do
26
+ instance_exec(&bl)
27
+ end
28
+ end
29
+ end
30
+
31
+ end # module TransactionPolicy
32
+ end # module Support
33
+ end # module Startback
@@ -19,3 +19,5 @@ require_relative 'support/logger'
19
19
  require_relative 'support/robustness'
20
20
  require_relative 'support/hooks'
21
21
  require_relative 'support/operation_runner'
22
+ require_relative 'support/transaction_policy'
23
+ require_relative 'support/transaction_manager'
@@ -1,8 +1,8 @@
1
1
  module Startback
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 8
5
- TINY = 3
4
+ MINOR = 10
5
+ TINY = 1
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
@@ -34,10 +34,25 @@ module Startback
34
34
  # A bit of logic to choose the best error message for the user
35
35
  # according to the error class
36
36
  self.body{|ex|
37
- ex = ex.root_cause if ex.is_a?(Finitio::TypeError)
38
- { code: ex.class.name, description: ex.message }.to_json
37
+ body_for(ex).to_json
39
38
  }
40
39
 
40
+ def body_for(ex)
41
+ ex = ex.root_cause if ex.is_a?(Finitio::TypeError)
42
+ body = { code: ex.class.name, description: ex.message }
43
+ return body unless ex.is_a?(Startback::Errors::Error)
44
+ return body unless ex.has_causes?
45
+
46
+ body[:causes] = ex.causes
47
+ .filter{|cause|
48
+ cause.is_a?(Startback::Errors::Error)
49
+ }
50
+ .map{|cause|
51
+ body_for(cause)
52
+ }
53
+ body
54
+ end
55
+
41
56
  end # class Shield
42
57
  end # module Web
43
58
  end # module Startback
@@ -68,7 +68,7 @@ module Startback
68
68
  end
69
69
 
70
70
  context 'the around feature with a class' do
71
- class TransactionManager
71
+ class SomeTransactionManager
72
72
  include Singleton
73
73
 
74
74
  def initialize
@@ -87,7 +87,7 @@ module Startback
87
87
 
88
88
  class RunnerTest3
89
89
  include OperationRunner
90
- around_run TransactionManager.instance
90
+ around_run SomeTransactionManager.instance
91
91
 
92
92
  def operation_world(op)
93
93
  { hello: "world" }
@@ -97,7 +97,7 @@ module Startback
97
97
  it 'calls the proc with expected parameters' do
98
98
  test = RunnerTest3.new
99
99
  got = test.run(op)
100
- expect(TransactionManager.instance.called).to eql(true)
100
+ expect(SomeTransactionManager.instance.called).to eql(true)
101
101
  expect(got).to eql({
102
102
  seen_hello: "world"
103
103
  })
@@ -154,4 +154,3 @@ module Startback
154
154
  end # module OperationRunner
155
155
  end # module Support
156
156
  end # module Startback
157
-
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+ module Startback
3
+ module Support
4
+ describe TransactionManager do
5
+ subject do
6
+ TransactionManager.new(db).call(nil, op) do
7
+ op.call
8
+ end
9
+ end
10
+
11
+ class FakeDatabase
12
+ def initialize
13
+ @called = false
14
+ end
15
+ attr_reader :called
16
+
17
+ def transaction
18
+ @called = true
19
+ yield
20
+ end
21
+ end
22
+
23
+ let(:db) do
24
+ FakeDatabase.new
25
+ end
26
+
27
+ context 'when called with a default operation' do
28
+ class OperationNotManagingTransactions < Startback::Operation
29
+ def call
30
+ 12
31
+ end
32
+ end
33
+
34
+ let(:op) do
35
+ OperationNotManagingTransactions.new
36
+ end
37
+
38
+ it 'calls db.transaction' do
39
+ expect(subject).to eql(12)
40
+ expect(db.called).to eql(true)
41
+ end
42
+ end
43
+
44
+ context 'when called with an operation that manages the transactions itself' do
45
+ class OperationManagingTransactions < Startback::Operation
46
+ self.transaction_policy = :within_call
47
+
48
+ def call
49
+ 12
50
+ end
51
+ end
52
+
53
+ let(:op) do
54
+ OperationManagingTransactions.new
55
+ end
56
+
57
+ it 'calls db.transaction' do
58
+ expect(subject).to eql(12)
59
+ expect(db.called).to eql(false)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: startback
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.3
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-25 00:00:00.000000000 Z
11
+ date: 2021-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -228,22 +228,22 @@ dependencies:
228
228
  name: puma
229
229
  requirement: !ruby/object:Gem::Requirement
230
230
  requirements:
231
- - - ">="
232
- - !ruby/object:Gem::Version
233
- version: 4.3.8
234
231
  - - ">="
235
232
  - !ruby/object:Gem::Version
236
233
  version: 5.3.1
234
+ - - "<"
235
+ - !ruby/object:Gem::Version
236
+ version: '6.0'
237
237
  type: :runtime
238
238
  prerelease: false
239
239
  version_requirements: !ruby/object:Gem::Requirement
240
240
  requirements:
241
- - - ">="
242
- - !ruby/object:Gem::Version
243
- version: 4.3.8
244
241
  - - ">="
245
242
  - !ruby/object:Gem::Version
246
243
  version: 5.3.1
244
+ - - "<"
245
+ - !ruby/object:Gem::Version
246
+ version: '6.0'
247
247
  - !ruby/object:Gem::Dependency
248
248
  name: jwt
249
249
  requirement: !ruby/object:Gem::Requirement
@@ -380,7 +380,6 @@ extra_rdoc_files: []
380
380
  files:
381
381
  - README.md
382
382
  - Rakefile
383
- - VERSION
384
383
  - lib/startback.rb
385
384
  - lib/startback/audit.rb
386
385
  - lib/startback/audit/prometheus.rb
@@ -411,6 +410,8 @@ files:
411
410
  - lib/startback/support/logger.rb
412
411
  - lib/startback/support/operation_runner.rb
413
412
  - lib/startback/support/robustness.rb
413
+ - lib/startback/support/transaction_manager.rb
414
+ - lib/startback/support/transaction_policy.rb
414
415
  - lib/startback/version.rb
415
416
  - lib/startback/web/api.rb
416
417
  - lib/startback/web/auto_caching.rb
@@ -438,6 +439,7 @@ files:
438
439
  - spec/unit/support/operation_runner/test_around_run.rb
439
440
  - spec/unit/support/operation_runner/test_before_after_call.rb
440
441
  - spec/unit/support/test_robusteness.rb
442
+ - spec/unit/support/test_transaction_manager.rb
441
443
  - spec/unit/test_event.rb
442
444
  - spec/unit/test_operation.rb
443
445
  - spec/unit/test_support.rb
@@ -470,7 +472,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
470
472
  - !ruby/object:Gem::Version
471
473
  version: '0'
472
474
  requirements: []
473
- rubygems_version: 3.2.15
475
+ rubygems_version: 3.2.32
474
476
  signing_key:
475
477
  specification_version: 4
476
478
  summary: Got Your Ruby Back
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.8.3