copy_tuner_client 0.4.5 → 0.4.6

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
- 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