tantot 0.1.5 → 0.1.6

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tantot.rb +7 -23
  3. data/lib/tantot/agent.rb +19 -0
  4. data/lib/tantot/agent/base.rb +71 -0
  5. data/lib/tantot/agent/block.rb +32 -0
  6. data/lib/tantot/agent/registry.rb +34 -0
  7. data/lib/tantot/agent/watcher.rb +46 -0
  8. data/lib/tantot/changes.rb +2 -3
  9. data/lib/tantot/config.rb +2 -2
  10. data/lib/tantot/errors.rb +6 -0
  11. data/lib/tantot/extensions/chewy.rb +66 -18
  12. data/lib/tantot/extensions/grape/middleware.rb +1 -1
  13. data/lib/tantot/manager.rb +31 -0
  14. data/lib/tantot/observe.rb +36 -31
  15. data/lib/tantot/railtie.rb +5 -0
  16. data/lib/tantot/strategy.rb +24 -0
  17. data/lib/tantot/{performer → strategy}/bypass.rb +2 -2
  18. data/lib/tantot/strategy/chewy.rb +33 -0
  19. data/lib/tantot/strategy/inline.rb +9 -0
  20. data/lib/tantot/strategy/sidekiq.rb +36 -0
  21. data/lib/tantot/version.rb +1 -1
  22. data/performance/profile.rb +12 -8
  23. data/spec/collector/block_spec.rb +33 -0
  24. data/spec/collector/options_spec.rb +211 -0
  25. data/spec/collector/watcher_spec.rb +180 -0
  26. data/spec/extensions/chewy_spec.rb +280 -78
  27. data/spec/sidekiq_spec.rb +38 -58
  28. data/spec/spec_helper.rb +27 -2
  29. data/spec/tantot_spec.rb +0 -370
  30. metadata +19 -15
  31. data/lib/tantot/collector.rb +0 -70
  32. data/lib/tantot/collector/base.rb +0 -46
  33. data/lib/tantot/collector/block.rb +0 -69
  34. data/lib/tantot/collector/watcher.rb +0 -67
  35. data/lib/tantot/formatter.rb +0 -10
  36. data/lib/tantot/formatter/compact.rb +0 -9
  37. data/lib/tantot/formatter/detailed.rb +0 -9
  38. data/lib/tantot/performer.rb +0 -24
  39. data/lib/tantot/performer/chewy.rb +0 -31
  40. data/lib/tantot/performer/inline.rb +0 -9
  41. data/lib/tantot/performer/sidekiq.rb +0 -21
  42. data/lib/tantot/registry.rb +0 -11
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tantot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - François-Pierre Bouchard
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-13 00:00:00.000000000 Z
11
+ date: 2016-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -157,30 +157,31 @@ files:
157
157
  - bin/console
158
158
  - bin/setup
159
159
  - lib/tantot.rb
160
+ - lib/tantot/agent.rb
161
+ - lib/tantot/agent/base.rb
162
+ - lib/tantot/agent/block.rb
163
+ - lib/tantot/agent/registry.rb
164
+ - lib/tantot/agent/watcher.rb
160
165
  - lib/tantot/changes.rb
161
- - lib/tantot/collector.rb
162
- - lib/tantot/collector/base.rb
163
- - lib/tantot/collector/block.rb
164
- - lib/tantot/collector/watcher.rb
165
166
  - lib/tantot/config.rb
166
167
  - lib/tantot/errors.rb
167
168
  - lib/tantot/extensions/chewy.rb
168
169
  - lib/tantot/extensions/grape/middleware.rb
169
- - lib/tantot/formatter.rb
170
- - lib/tantot/formatter/compact.rb
171
- - lib/tantot/formatter/detailed.rb
170
+ - lib/tantot/manager.rb
172
171
  - lib/tantot/observe.rb
173
- - lib/tantot/performer.rb
174
- - lib/tantot/performer/bypass.rb
175
- - lib/tantot/performer/chewy.rb
176
- - lib/tantot/performer/inline.rb
177
- - lib/tantot/performer/sidekiq.rb
178
172
  - lib/tantot/railtie.rb
179
- - lib/tantot/registry.rb
173
+ - lib/tantot/strategy.rb
174
+ - lib/tantot/strategy/bypass.rb
175
+ - lib/tantot/strategy/chewy.rb
176
+ - lib/tantot/strategy/inline.rb
177
+ - lib/tantot/strategy/sidekiq.rb
180
178
  - lib/tantot/version.rb
181
179
  - lib/tantot/watcher.rb
182
180
  - performance/profile.rb
183
181
  - spec/changes_spec.rb
182
+ - spec/collector/block_spec.rb
183
+ - spec/collector/options_spec.rb
184
+ - spec/collector/watcher_spec.rb
184
185
  - spec/extensions/chewy_spec.rb
185
186
  - spec/sidekiq_spec.rb
186
187
  - spec/spec_helper.rb
@@ -212,6 +213,9 @@ specification_version: 4
212
213
  summary: Delayed, grouped and compact ActiveRecord callbacks
213
214
  test_files:
214
215
  - spec/changes_spec.rb
216
+ - spec/collector/block_spec.rb
217
+ - spec/collector/options_spec.rb
218
+ - spec/collector/watcher_spec.rb
215
219
  - spec/extensions/chewy_spec.rb
216
220
  - spec/sidekiq_spec.rb
217
221
  - spec/spec_helper.rb
@@ -1,70 +0,0 @@
1
- require 'tantot/collector/base'
2
- require 'tantot/collector/watcher'
3
- require 'tantot/collector/block'
4
-
5
- COLLECTOR_CLASSES = [Tantot::Collector::Block, Tantot::Collector::Watcher]
6
-
7
- module Tantot
8
- module Collector
9
- class Manager
10
- def initialize
11
- @collectors = {}
12
- end
13
-
14
- def register_watch(context, block)
15
- resolve!(context).register_watch(context, block)
16
- end
17
-
18
- def run(&block)
19
- yield
20
- ensure
21
- sweep
22
- end
23
-
24
- def push(context, instance, mutations)
25
- collector = resolve!(context)
26
- Tantot.logger.debug do
27
- mutate = mutations.size.zero? ? 'destroy' : "#{mutations.size} mutations(s)"
28
- "[Tantot] [Collecting] [#{collector.class.name.demodulize}] #{mutate} on <#{instance.class.name}:#{instance.id}> for <#{collector.debug_context(context)}>"
29
- end
30
- collector.push(context, instance, mutations)
31
- sweep if Tantot.config.sweep_on_push
32
- end
33
-
34
- def sweep(performer_name = nil)
35
- @collectors.values.each {|collector| collector.sweep(performer_name)}
36
- end
37
-
38
- def perform(context, changes)
39
- collector = resolve!(context)
40
- Tantot.logger.debug { "[Tantot] [Run] [#{collector.class.name.demodulize}] #{collector.debug_perform(context, changes)}" }
41
- collector.perform(context, changes)
42
- end
43
-
44
- def marshal(context, changes)
45
- collector = resolve!(context)
46
- context, changes = collector.marshal(context, changes)
47
- context[:collector_class] = collector.class
48
- [context, changes]
49
- end
50
-
51
- def unmarshal(context, changes)
52
- context.deep_symbolize_keys!
53
- collector_class = context[:collector_class].constantize
54
- collector = @collectors[collector_class] || @collectors[collector_class] = collector_class.new
55
- collector.unmarshal(context, changes)
56
- end
57
-
58
- def resolve(context)
59
- collector_class = COLLECTOR_CLASSES.find {|c| c.manages?(context)}
60
- return nil unless collector_class
61
- @collectors[collector_class] || @collectors[collector_class] = collector_class.new
62
- end
63
-
64
- def resolve!(context)
65
- resolve(context) || (raise "No collector manages current context: #{context.inspect}")
66
- end
67
-
68
- end
69
- end
70
- end
@@ -1,46 +0,0 @@
1
- module Tantot
2
- module Collector
3
- class Base
4
- class_attribute :context_key
5
-
6
- def self.manages?(context)
7
- context.key?(self.context_key)
8
- end
9
-
10
- def register_watch(context, block)
11
- raise NotImplementedError
12
- end
13
-
14
- def push(context, instance, mutations)
15
- formatter = Tantot::Formatter.resolve(context[:options][:format] || Tantot.config.format).new
16
- attribute_hash = get_stash(context, instance)
17
- mutations.each do |attr, changes|
18
- attribute_hash[attr] = formatter.push(attribute_hash[attr], context, changes)
19
- end
20
- end
21
-
22
- def sweep(performer_name)
23
- if @stash.any?
24
- Tantot.logger.debug { "[Tantot] [Sweeping] [#{self.class.name.demodulize}] #{debug_state}" }
25
- @stash.each do |id, changes|
26
- context = Tantot.registry.watch_config[id][:context]
27
- performer = Tantot::Performer.resolve(performer_name || context[:options][:performer] || Tantot.config.performer).new
28
- Tantot.logger.debug { "[Tantot] [Performer] [#{self.class.name.demodulize}] [#{performer.class.name.demodulize}] #{debug_state(Hash[id, changes])}" }
29
- performer.run(context, changes)
30
- end
31
- @stash.clear
32
- end
33
- end
34
-
35
- def debug_changes_for_model(model, changes_by_id)
36
- "#{model.name}#{changes_by_id.keys.inspect}"
37
- end
38
-
39
- protected
40
-
41
- def get_stash(context, instance)
42
- raise NotImplementedError
43
- end
44
- end
45
- end
46
- end
@@ -1,69 +0,0 @@
1
- module Tantot
2
- module Collector
3
- class Block < Base
4
- self.context_key = :block_id
5
-
6
- def initialize
7
- @stash = Hash.new do |block_id_hash, block_id|
8
- block_id_hash[block_id] = Hash.new do |id_hash, id|
9
- id_hash[id] = {}
10
- end
11
- end
12
- end
13
-
14
- def register_watch(context, block)
15
- Tantot.registry.watch_config[context[:block_id]] = {context: context, block: block}
16
- end
17
-
18
- def perform(context, changes_by_id)
19
- watch_config = Tantot.registry.watch_config[context[:block_id]]
20
- watch_config[:context][:model].instance_exec(Tantot::Changes::ById.new(changes_by_id), &watch_config[:block])
21
- end
22
-
23
- def marshal(context, changes_by_id)
24
- [context, changes_by_id]
25
- end
26
-
27
- def unmarshal(context, changes_by_id)
28
- changes_by_id = changes_by_id.each.with_object({}) do |(id, changes), change_hash|
29
- change_hash[id.to_i] = changes
30
- end
31
- [context, changes_by_id]
32
- end
33
-
34
- def debug_block(block)
35
- location, line = block.source_location
36
- short_path = defined?(Rails) ? Pathname.new(location).relative_path_from(Rails.root).to_s : location
37
- "block @ #{short_path}##{line}"
38
- end
39
-
40
- def debug_context(context)
41
- block = Tantot.registry.watch_config[context[:block_id]][:block]
42
- debug_block(block)
43
- end
44
-
45
- def debug_changes(watch_config, changes_by_id)
46
- "#{debug_changes_for_model(watch_config[:context][:model], changes_by_id)} for #{debug_block(watch_config[:block])}"
47
- end
48
-
49
- def debug_state(stash = @stash)
50
- stash.collect do |block_id, changes_by_id|
51
- watch_config = Tantot.registry.watch_config[block_id]
52
- debug_changes(watch_config, changes_by_id)
53
- end.join(" / ")
54
- end
55
-
56
- def debug_perform(context, changes_by_id)
57
- watch_config = Tantot.registry.watch_config[context[:block_id]]
58
- debug_changes(watch_config, changes_by_id)
59
- end
60
-
61
- protected
62
-
63
- def get_stash(context, instance)
64
- @stash[context[:block_id]][instance.id]
65
- end
66
-
67
- end
68
- end
69
- end
@@ -1,67 +0,0 @@
1
- module Tantot
2
- module Collector
3
- class Watcher < Base
4
- self.context_key = :watcher
5
-
6
- def initialize
7
- @stash = Hash.new do |watcher_hash, watcher|
8
- watcher_hash[watcher] = Hash.new do |model_hash, model|
9
- model_hash[model] = Hash.new do |id_hash, id|
10
- id_hash[id] = {}
11
- end
12
- end
13
- end
14
- end
15
-
16
- def register_watch(context, block)
17
- Tantot.registry.watch_config[context[:watcher]] = {context: context}
18
- end
19
-
20
- def perform(context, changes_by_model)
21
- context[:watcher].new.perform(Tantot::Changes::ByModel.new(changes_by_model))
22
- end
23
-
24
- def marshal(context, changes_by_model)
25
- changes_by_model = changes_by_model.each.with_object({}) do |(model_class, changes), hash|
26
- hash[model_class.name] = changes
27
- end
28
- [context, changes_by_model]
29
- end
30
-
31
- def unmarshal(context, changes_by_model)
32
- context[:watcher] = context[:watcher].constantize
33
- changes_by_model = changes_by_model.each.with_object({}) do |(model_class_name, changes_by_id), model_hash|
34
- model_hash[model_class_name.constantize] = changes_by_id.each.with_object({}) do |(id, changes), change_hash|
35
- change_hash[id.to_i] = changes
36
- end
37
- end
38
- [context, changes_by_model]
39
- end
40
-
41
- def debug_context(context)
42
- context[:watcher].name
43
- end
44
-
45
- def debug_changes(watcher, changes_by_model)
46
- "#{watcher.name}(#{changes_by_model.collect {|model, changes_by_id| debug_changes_for_model(model, changes_by_id)}.join(" & ")})"
47
- end
48
-
49
- def debug_state(stash = @stash)
50
- stash.collect {|watcher, changes_by_model| debug_changes(watcher, changes_by_model)}.flatten.join(" / ")
51
- end
52
-
53
- def debug_perform(context, changes_by_model)
54
- debug_changes(context[:watcher], changes_by_model)
55
- end
56
-
57
- protected
58
-
59
- def get_stash(context, instance)
60
- watcher = context[:watcher]
61
- model = context[:model]
62
- @stash[watcher][model][instance.id]
63
- end
64
-
65
- end
66
- end
67
- end
@@ -1,10 +0,0 @@
1
- require 'tantot/formatter/compact'
2
- require 'tantot/formatter/detailed'
3
-
4
- module Tantot
5
- module Formatter
6
- def self.resolve(name)
7
- "Tantot::Formatter::#{name.to_s.camelize}".safe_constantize or raise "Can't find formatter class `#{name}`"
8
- end
9
- end
10
- end
@@ -1,9 +0,0 @@
1
- module Tantot
2
- module Formatter
3
- class Compact
4
- def push(change_array, context, changes)
5
- change_array.nil? ? changes : change_array | changes
6
- end
7
- end
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module Tantot
2
- module Formatter
3
- class Detailed
4
- def push(change_array, context, changes)
5
- change_array.nil? ? [changes] : change_array.push(changes)
6
- end
7
- end
8
- end
9
- end
@@ -1,24 +0,0 @@
1
- require 'tantot/performer/bypass'
2
- require 'tantot/performer/inline'
3
-
4
- begin
5
- require 'chewy'
6
- require 'tantot/performer/chewy'
7
- rescue LoadError
8
- nil
9
- end
10
-
11
- begin
12
- require 'sidekiq'
13
- require 'tantot/performer/sidekiq'
14
- rescue LoadError
15
- nil
16
- end
17
-
18
- module Tantot
19
- module Performer
20
- def self.resolve(name)
21
- "Tantot::Performer::#{name.to_s.camelize}".safe_constantize or raise "Can't find performer class `#{name}`"
22
- end
23
- end
24
- end
@@ -1,31 +0,0 @@
1
- module Tantot
2
- module Performer
3
- class Chewy
4
- class Worker
5
- include ::Sidekiq::Worker
6
-
7
- def perform(context, changes)
8
- context, changes = Tantot.collector.unmarshal(context, changes)
9
- ::Chewy.strategy(context[:chewy_strategy]) do
10
- Tantot.collector.perform(context, changes)
11
- end
12
- end
13
- end
14
-
15
- def run(context, changes)
16
- case ::Chewy.strategy.current.name
17
- when :atomic, :urgent
18
- Tantot::Performer::Inline.new.run(context, changes)
19
- when /sidekiq/
20
- context, changes = Tantot.collector.marshal(context.merge({chewy_strategy: ::Chewy.strategy.current.name}), changes)
21
- Tantot::Performer::Chewy::Worker.perform_async(context, changes)
22
- when :bypass
23
- return
24
- else
25
- # No strategy defined, do an Inline run and let Chewy fail
26
- Tantot::Performer::Inline.new.run(context, changes)
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,9 +0,0 @@
1
- module Tantot
2
- module Performer
3
- class Inline
4
- def run(context, changes)
5
- Tantot.collector.perform(context, changes)
6
- end
7
- end
8
- end
9
- end
@@ -1,21 +0,0 @@
1
- module Tantot
2
- module Performer
3
- class Sidekiq
4
- class Worker
5
- include ::Sidekiq::Worker
6
-
7
- def perform(context, changes)
8
- context, changes = Tantot.collector.unmarshal(context, changes)
9
- Tantot.collector.perform(context, changes)
10
- end
11
- end
12
-
13
- def run(context, changes)
14
- queue = context[:options][:queue] || Tantot.config.sidekiq_queue
15
- ::Sidekiq::Client.push('class' => Tantot::Performer::Sidekiq::Worker,
16
- 'args' => Tantot.collector.marshal(context, changes),
17
- 'queue' => queue)
18
- end
19
- end
20
- end
21
- end