copy_tuner_client 0.4.5 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ee5536e5d0fc51ab6b81a083012470abf8613093
4
- data.tar.gz: d1d020eba3c032c6ea69064de37bad95716dad73
2
+ SHA256:
3
+ metadata.gz: bea0580a939cf024f1fdf8591aaa72956c1e3aeabdea1609a8f97d3ebb544890
4
+ data.tar.gz: 9beccd0ea02ef6ee6b5283ce60ac442b1d6bcd3c5876907bcacb899ce5fbabf8
5
5
  SHA512:
6
- metadata.gz: e93195318a86dd584dc10cf3a2c3fac2bb8deb312ad262272b18b970c7a44e0c27a70c1d12b0badb9d373a52ab0eb4d10f7a7744ce3556f7741c359db97a9387
7
- data.tar.gz: ee74c4a2962b530f349921f91d39d36b7de70feb241f4eaa86cf7ed09b46e08899d09d997c45f9cdd585e7e1edd320dbf9adbf61d37e2bb6e962f64f092c2450
6
+ metadata.gz: 5efb8eb5d2ca1db876223bf4ab29307caf2104f83cff25d4583f74e409cbb30252b7cc9b6b6f28a4c2ca0d8e73671e6014ec04a8dd137b98b20b2cfd3b4099e2
7
+ data.tar.gz: 17b5e90d9091dc0b95bbba213d5645a25b250f9c44e8ef6dd302447ec7de2e0d49b07c3fb022d0748ae8fdbf857716573daf8488db2f3ce033a110ef376c34bd
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.4.6
2
+ - changes
3
+ - Performance imporovement (sync with server asynchronously)
4
+ - Add config.middleware_position
5
+
1
6
  ## 0.4.5
2
7
  - changes
3
8
  - Fix deprecated css.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- copy_tuner_client (0.4.5)
4
+ copy_tuner_client (0.4.6)
5
5
  i18n (>= 0.5.0)
6
6
  json
7
7
 
@@ -12,10 +12,6 @@ module CopyTunerClient
12
12
  # Must act like a hash and return sensible values for all CopyTuner
13
13
  # configuration options. Usually set when {.configure} is called.
14
14
  attr_accessor :configuration
15
-
16
- # @return [Poller] instance used to poll for changes.
17
- # This is set when {.configure} is called.
18
- attr_accessor :poller
19
15
  end
20
16
 
21
17
  # Issues a new deploy, marking all draft blurbs as published.
@@ -30,11 +26,6 @@ module CopyTunerClient
30
26
  cache.export
31
27
  end
32
28
 
33
- # Starts the polling process.
34
- def self.start_poller
35
- poller.start
36
- end
37
-
38
29
  # Flush queued changed synchronously
39
30
  def self.flush
40
31
  cache.flush
@@ -48,6 +39,10 @@ module CopyTunerClient
48
39
  CopyTunerClient.configuration.client
49
40
  end
50
41
 
42
+ def self.poller
43
+ CopyTunerClient.configuration.poller
44
+ end
45
+
51
46
  # Call this method to modify defaults in your initializers.
52
47
  #
53
48
  # @example
@@ -13,15 +13,16 @@ module CopyTunerClient
13
13
  # @param options [Hash]
14
14
  # @option options [Logger] :logger where errors should be logged
15
15
  def initialize(client, options)
16
- @blurbs = {}
17
16
  @client = client
18
- @downloaded = false
19
17
  @logger = options[:logger]
20
18
  @mutex = Mutex.new
21
- @queued = {}
22
- @started = false
23
19
  @exclude_key_regexp = options[:exclude_key_regexp]
24
20
  @locales = Array(options[:locales]).map(&:to_s)
21
+ # mutable states
22
+ @blurbs = {}
23
+ @queued = {}
24
+ @started = false
25
+ @downloaded = false
25
26
  end
26
27
 
27
28
  # Returns content for the given blurb.
@@ -47,13 +47,15 @@ module CopyTunerClient
47
47
  connect(s3_host) do |http|
48
48
  request = Net::HTTP::Get.new(uri(download_resource))
49
49
  request['If-None-Match'] = @etag
50
+ log 'Start downloading translations'
51
+ t = Time.now
50
52
  response = http.request(request)
51
-
53
+ t_ms = ((Time.now - t) * 1000).to_i
52
54
  if check response
53
- log 'Downloaded translations'
55
+ log "Downloaded translations (#{t_ms}ms)"
54
56
  yield JSON.parse(response.body)
55
57
  else
56
- log 'No new translations'
58
+ log "No new translations (#{t_ms}ms)"
57
59
  end
58
60
 
59
61
  @etag = response['ETag']
@@ -93,6 +93,9 @@ module CopyTunerClient
93
93
  # @return [Boolean] disable middleware setting
94
94
  attr_accessor :disable_middleware
95
95
 
96
+ # {before: OtherMiddleware} or {after: OtherMiddleware}
97
+ attr_accessor :middleware_position
98
+
96
99
  # @return [Boolean] disable download translation for test enviroment
97
100
  attr_accessor :disable_test_translation
98
101
 
@@ -105,6 +108,8 @@ module CopyTunerClient
105
108
  # @return [Client] instance used to communicate with a CopyTuner Server.
106
109
  attr_accessor :client
107
110
 
111
+ attr_accessor :poller
112
+
108
113
  # @return [Boolean] To enable inline-translation-mode, set true.
109
114
  attr_accessor :inline_translation
110
115
 
@@ -230,16 +235,25 @@ module CopyTunerClient
230
235
 
231
236
  self.client ||= Client.new(to_hash)
232
237
  self.cache ||= Cache.new(client, to_hash)
233
- poller = Poller.new(cache, to_hash)
234
- process_guard = ProcessGuard.new(cache, poller, to_hash)
238
+ @poller = Poller.new(cache, to_hash)
239
+ process_guard = ProcessGuard.new(cache, @poller, to_hash)
235
240
  I18n.backend = I18nBackend.new(cache)
236
241
 
237
242
  if enable_middleware?
238
243
  logger.info "Using copytuner sync middleware"
239
- middleware.use RequestSync, :cache => cache, :interval => sync_interval, :ignore_regex => sync_ignore_path_regex
240
- middleware.use CopyTunerClient::CopyrayMiddleware
244
+ request_sync_options = {:poller => @poller, :cache => cache, :interval => sync_interval, :ignore_regex => sync_ignore_path_regex}
245
+ if middleware_position.is_a?(Hash) && middleware_position[:before]
246
+ middleware.insert_before middleware_position[:before], RequestSync, request_sync_options
247
+ middleware.insert_before middleware_position[:before], CopyTunerClient::CopyrayMiddleware
248
+ elsif middleware_position.is_a?(Hash) && middleware_position[:after]
249
+ middleware.insert_after middleware_position[:after], RequestSync, request_sync_options
250
+ middleware.insert_after middleware_position[:after], CopyTunerClient::CopyrayMiddleware
251
+ else
252
+ middleware.use RequestSync, request_sync_options
253
+ middleware.use CopyTunerClient::CopyrayMiddleware
254
+ end
241
255
  else
242
- logger.info "[[[Warn]]] Not useing copytuner sync middleware" unless middleware
256
+ logger.info "[[[Warn]]] Not using copytuner sync middleware" unless middleware
243
257
  end
244
258
 
245
259
  @applied = true
@@ -1,5 +1,6 @@
1
1
  require 'thread'
2
2
  require 'copy_tuner_client/cache'
3
+ require 'copy_tuner_client/queue_with_timeout'
3
4
 
4
5
  module CopyTunerClient
5
6
  # Starts a background thread that continually resynchronizes with the remote
@@ -12,16 +13,34 @@ module CopyTunerClient
12
13
  @cache = cache
13
14
  @polling_delay = options[:polling_delay]
14
15
  @logger = options[:logger]
15
- @stop = false
16
+ @command_queue = CopyTunerClient::QueueWithTimeout.new
17
+ @mutex = Mutex.new
18
+ @thread = nil
16
19
  end
17
20
 
18
21
  def start
19
- @logger.info 'start poller'
20
- Thread.new { poll } or logger.error("Couldn't start poller thread")
22
+ @mutex.synchronize do
23
+ if @thread.nil?
24
+ @logger.info 'start poller thread'
25
+ @thread = Thread.new { poll } or logger.error("Couldn't start poller thread")
26
+ end
27
+ end
21
28
  end
22
29
 
23
30
  def stop
24
- @stop = true
31
+ @mutex.synchronize do
32
+ @command_queue.uniq_push(:stop)
33
+ @thread.join if @thread
34
+ @thread = nil
35
+ end
36
+ end
37
+
38
+ def start_sync
39
+ @command_queue.uniq_push(:sync)
40
+ end
41
+
42
+ def wait_for_download
43
+ @cache.wait_for_download
25
44
  end
26
45
 
27
46
  private
@@ -29,17 +48,19 @@ module CopyTunerClient
29
48
  attr_reader :cache, :logger, :polling_delay
30
49
 
31
50
  def poll
32
- until @stop
51
+ loop do
33
52
  cache.sync
34
53
  logger.flush if logger.respond_to?(:flush)
35
- delay
54
+ begin
55
+ command = @command_queue.pop_with_timeout(polling_delay)
56
+ break if command == :stop
57
+ rescue ThreadError
58
+ # timeout
59
+ end
36
60
  end
61
+ @logger.info 'stop poller thread'
37
62
  rescue InvalidApiKey => error
38
63
  logger.error(error.message)
39
64
  end
40
-
41
- def delay
42
- sleep(polling_delay)
43
- end
44
65
  end
45
66
  end
@@ -0,0 +1,50 @@
1
+ module CopyTunerClient
2
+ # https://spin.atomicobject.com/2014/07/07/ruby-queue-pop-timeout/
3
+ class QueueWithTimeout
4
+ def initialize
5
+ @mutex = Mutex.new
6
+ @queue = []
7
+ @received = ConditionVariable.new
8
+ end
9
+
10
+ def <<(x)
11
+ @mutex.synchronize do
12
+ @queue << x
13
+ @received.signal
14
+ end
15
+ end
16
+
17
+ def uniq_push(x)
18
+ @mutex.synchronize do
19
+ unless @queue.member?(x)
20
+ @queue << x
21
+ @received.signal
22
+ end
23
+ end
24
+ end
25
+
26
+ def pop(non_block = false)
27
+ pop_with_timeout(non_block ? 0 : nil)
28
+ end
29
+
30
+ def pop_with_timeout(timeout = nil)
31
+ @mutex.synchronize do
32
+ if timeout.nil?
33
+ # wait indefinitely until there is an element in the queue
34
+ while @queue.empty?
35
+ @received.wait(@mutex)
36
+ end
37
+ elsif @queue.empty? && timeout != 0
38
+ # wait for element or timeout
39
+ timeout_time = timeout + Time.now.to_f
40
+ while @queue.empty? && (remaining_time = timeout_time - Time.now.to_f) > 0
41
+ @received.wait(@mutex, remaining_time)
42
+ end
43
+ end
44
+ #if we're still empty after the timeout, raise exception
45
+ raise ThreadError, "queue empty" if @queue.empty?
46
+ @queue.shift
47
+ end
48
+ end
49
+ end
50
+ end
@@ -16,10 +16,12 @@ module CopyTunerClient
16
16
  # @option options [Cache] :cache agent that should be flushed after each request
17
17
  def initialize(app, options)
18
18
  @app = app
19
+ @poller = options[:poller]
19
20
  @cache = options[:cache]
20
21
  @interval = options[:interval]
21
22
  @ignore_regex = options[:ignore_regex]
22
23
  @last_synced = options[:last_synced]
24
+ @first = true
23
25
  end
24
26
 
25
27
  attr_accessor :last_synced
@@ -30,9 +32,16 @@ module CopyTunerClient
30
32
  if /^\/copytuner/ =~ ::Rack::Request.new(env).path_info
31
33
  dup._call(env)
32
34
  else
33
- @cache.download unless cancel_sync?(env)
35
+ first_request = @first
36
+ if first_request
37
+ @first = false
38
+ @cache.download
39
+ end
40
+
41
+ cancel_sync = cancel_sync?(env)
34
42
  response = @app.call(env)
35
- @cache.flush unless cancel_sync?(env)
43
+ @poller.start_sync unless first_request || cancel_sync
44
+
36
45
  update_last_synced unless in_interval?
37
46
  response
38
47
  end
@@ -140,5 +149,9 @@ module CopyTunerClient
140
149
  def update_last_synced
141
150
  @last_synced = Time.now.utc
142
151
  end
152
+
153
+ def logger
154
+ CopyTunerClient.configuration.logger
155
+ end
143
156
  end
144
157
  end
@@ -1,6 +1,6 @@
1
1
  module CopyTunerClient
2
2
  # Client version
3
- VERSION = '0.4.5'.freeze
3
+ VERSION = '0.4.6'.freeze
4
4
 
5
5
  # API version being used to communicate with the server
6
6
  API_VERSION = '2.0'.freeze
@@ -95,14 +95,4 @@ describe CopyTunerClient::Poller do
95
95
 
96
96
  expect(logger).to have_received(:flush).at_least_once
97
97
  end
98
-
99
- it "starts from the top-level constant" do
100
- poller = build_poller
101
- CopyTunerClient.poller = poller
102
- poller.stubs(:start)
103
-
104
- CopyTunerClient.start_poller
105
-
106
- expect(poller).to have_received(:start)
107
- end
108
98
  end
@@ -1,91 +1,81 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe CopyTunerClient::RequestSync do
4
-
4
+ let(:poller) { {} }
5
5
  let(:cache) { {} }
6
6
  let(:response) { 'response' }
7
7
  let(:env) { 'env' }
8
8
  let(:app) { stub('app', :call => response) }
9
- before { cache.stubs(:flush => nil, :download => nil) }
10
- subject { CopyTunerClient::RequestSync.new(app, :cache => cache, :interval => 0) }
9
+ before do
10
+ cache.stubs(:flush => nil, :download => nil)
11
+ poller.stubs(:start_sync => nil)
12
+ end
13
+ subject { CopyTunerClient::RequestSync.new(app, :poller => poller, :cache => cache, :interval => 0) }
11
14
 
12
15
  it "invokes the upstream app" do
13
16
  result = subject.call(env)
14
17
  expect(app).to have_received(:call).with(env)
15
18
  expect(result).to eq(response)
16
19
  end
17
-
18
- it "flushes defaults" do
19
- subject.call(env)
20
- expect(cache).to have_received(:flush)
21
- end
22
-
23
- it "downloads new copy" do
24
- subject.call(env)
25
- expect(cache).to have_received(:download)
26
- end
27
20
  end
28
21
 
29
22
  describe CopyTunerClient::RequestSync, 'serving assets' do
30
23
  let(:env) do
31
24
  { "PATH_INFO" => '/assets/choper.png' }
32
25
  end
26
+ let(:poller) { {} }
33
27
  let(:cache) { {} }
34
28
  let(:response) { 'response' }
35
29
  let(:app) { stub('app', :call => response) }
36
- before { cache.stubs(:flush => nil, :download => nil) }
37
- subject { CopyTunerClient::RequestSync.new(app, :cache => cache, :interval => 0) }
30
+ before do
31
+ cache.stubs(:flush => nil, :download => nil)
32
+ poller.stubs(:start_sync => nil)
33
+ end
34
+ subject { CopyTunerClient::RequestSync.new(app, :poller => poller, :cache => cache, :interval => 0) }
38
35
 
39
- it "does not flush defaults" do
36
+ it "don't start sync" do
40
37
  subject.call(env)
41
- expect(cache).to have_received(:flush).never
42
- end
43
- it "does not download new copy" do
38
+ expect(cache).to have_received(:download).once
44
39
  subject.call(env)
45
- expect(cache).to have_received(:download).never
40
+ expect(poller).to have_received(:start_sync).never
46
41
  end
47
42
  end
48
43
 
49
44
  describe CopyTunerClient::RequestSync do
45
+ let(:poller) { {} }
50
46
  let(:cache) { {} }
51
47
  let(:response) { 'response' }
52
48
  let(:env) { 'env' }
53
49
  let(:app) { stub('app', :call => response) }
54
- before { cache.stubs(:flush => nil, :download => nil) }
50
+ subject { CopyTunerClient::RequestSync.new(app, :poller => poller, :cache => cache, :interval => 10) }
51
+ before do
52
+ cache.stubs(:flush => nil, :download => nil)
53
+ poller.stubs(:start_sync => nil)
54
+ end
55
55
 
56
- context 'in interval request' do
57
- subject { CopyTunerClient::RequestSync.new(app, :cache => cache, :interval => 10, :last_synced => Time.now) }
58
- it "does not flush defaults" do
59
- subject.call(env)
60
- expect(cache).to have_received(:flush).never
61
- end
62
- it "does not download new copy" do
56
+ context "first request" do
57
+ it "download" do
63
58
  subject.call(env)
64
- expect(cache).to have_received(:download).never
59
+ expect(cache).to have_received(:download).once
65
60
  end
66
61
  end
67
62
 
68
- context 'over interval request' do
69
- subject { CopyTunerClient::RequestSync.new(app, :cache => cache, :interval => 10, :last_synced => Time.now - 60) }
70
- it "flushes defaults" do
63
+ context 'in interval request' do
64
+ it "does not start sync for the second time" do
71
65
  subject.call(env)
72
- expect(cache).to have_received(:flush)
73
- end
74
- it "downloads new copy" do
66
+ expect(cache).to have_received(:download).once
75
67
  subject.call(env)
76
- expect(cache).to have_received(:download)
68
+ expect(poller).to have_received(:start_sync).never
77
69
  end
78
70
  end
79
71
 
80
- context "first request" do
81
- subject { CopyTunerClient::RequestSync.new(app, :cache => cache, :interval => 10) }
82
- it "flushes defaults" do
72
+ context 'over interval request' do
73
+ it "start sync for the second time" do
83
74
  subject.call(env)
84
- expect(cache).to have_received(:flush)
85
- end
86
- it "downloads new copy" do
75
+ expect(cache).to have_received(:download).once
76
+ subject.last_synced = Time.now - 60
87
77
  subject.call(env)
88
- expect(cache).to have_received(:download)
78
+ expect(poller).to have_received(:start_sync).once
89
79
  end
90
80
  end
91
81
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: copy_tuner_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - SonicGarden
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-21 00:00:00.000000000 Z
11
+ date: 2018-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: i18n
@@ -263,6 +263,7 @@ files:
263
263
  - lib/copy_tuner_client/poller.rb
264
264
  - lib/copy_tuner_client/prefixed_logger.rb
265
265
  - lib/copy_tuner_client/process_guard.rb
266
+ - lib/copy_tuner_client/queue_with_timeout.rb
266
267
  - lib/copy_tuner_client/rails.rb
267
268
  - lib/copy_tuner_client/request_sync.rb
268
269
  - lib/copy_tuner_client/simple_form_extention.rb
@@ -319,7 +320,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
319
320
  version: '0'
320
321
  requirements: []
321
322
  rubyforge_project:
322
- rubygems_version: 2.5.2.2
323
+ rubygems_version: 2.7.6
323
324
  signing_key:
324
325
  specification_version: 4
325
326
  summary: Client for the CopyTuner copy management service