asynchronic 3.0.1 → 4.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +7 -10
  3. data/README.md +1 -2
  4. data/asynchronic.gemspec +2 -3
  5. data/lib/asynchronic.rb +8 -0
  6. data/lib/asynchronic/data_store/in_memory.rb +17 -15
  7. data/lib/asynchronic/data_store/key.rb +3 -3
  8. data/lib/asynchronic/data_store/lazy_value.rb +5 -3
  9. data/lib/asynchronic/data_store/redis.rb +22 -14
  10. data/lib/asynchronic/data_store/scoped_store.rb +18 -19
  11. data/lib/asynchronic/environment.rb +3 -3
  12. data/lib/asynchronic/error.rb +2 -3
  13. data/lib/asynchronic/garbage_collector.rb +2 -1
  14. data/lib/asynchronic/job.rb +12 -12
  15. data/lib/asynchronic/notifier/broadcaster.rb +8 -4
  16. data/lib/asynchronic/process.rb +42 -40
  17. data/lib/asynchronic/queue_engine/in_memory.rb +17 -11
  18. data/lib/asynchronic/queue_engine/ost.rb +7 -5
  19. data/lib/asynchronic/queue_engine/synchronic.rb +19 -7
  20. data/lib/asynchronic/version.rb +1 -1
  21. data/lib/asynchronic/worker.rb +7 -10
  22. data/spec/data_store/data_store_examples.rb +17 -9
  23. data/spec/data_store/in_memory_spec.rb +0 -2
  24. data/spec/data_store/key_spec.rb +1 -1
  25. data/spec/data_store/lazy_value_examples.rb +7 -5
  26. data/spec/data_store/redis_spec.rb +4 -10
  27. data/spec/expectations.rb +2 -2
  28. data/spec/facade_spec.rb +3 -3
  29. data/spec/jobs.rb +10 -10
  30. data/spec/minitest_helper.rb +5 -12
  31. data/spec/process/life_cycle_examples.rb +25 -23
  32. data/spec/process/life_cycle_in_memory_spec.rb +0 -1
  33. data/spec/process/life_cycle_redis_spec.rb +0 -1
  34. data/spec/queue_engine/in_memory_spec.rb +1 -3
  35. data/spec/queue_engine/ost_spec.rb +1 -7
  36. data/spec/queue_engine/queue_engine_examples.rb +17 -9
  37. data/spec/queue_engine/synchronic_spec.rb +1 -1
  38. data/spec/worker/in_memory_spec.rb +1 -2
  39. data/spec/worker/redis_spec.rb +0 -6
  40. data/spec/worker/worker_examples.rb +6 -4
  41. metadata +11 -20
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0e0f25f70fa41da06affe41aa2fb639b7bfd542a
4
- data.tar.gz: 0a59f33dece383cd47df04ee457221101bbed618
2
+ SHA256:
3
+ metadata.gz: 1927d93fad4703789a566429a5e31767e332ca9f17cbe94db92f899587398a38
4
+ data.tar.gz: 64a6f3c8fc8d9248166ba6b1fc0dcc4f9d51a6229f3a2f3d4b99b645dd92059f
5
5
  SHA512:
6
- metadata.gz: 80d20d5b4ca50a04ed124b03d7b76000847a433877b45bb7bd2dc77e22f0984ec6f4215af76bd5a881a5bd550b67725a3a1d856698f96d878f9f55725e181c67
7
- data.tar.gz: 51c7ed3e8686731277c31fbdea1bcb2bfc62c10959fbbcab7cf46a4d0cf6dc7f7ff2c6063eb5eea4809aeed773a150593787b1fdef6ca1d7afef8cf2c4531ed1
6
+ metadata.gz: '0207949f35f7e91d8b5506d469e85f023071a5bbfbc17631fbbf4f5da76e22f2224d4bc08ecf347fe0b34f06e08d063c3db1e1b7d0c81a6ff164c4d9e1ba21a7'
7
+ data.tar.gz: 17f48dc8a1bb5aed62d28aa5a22d1c6f6271fa5b39a0032fce098148c22185a88803e741760b8aa8b35a3b765d5675136b9808b62e996bd0138d8cac5d866b2a
data/.travis.yml CHANGED
@@ -4,12 +4,13 @@ rvm:
4
4
  - 2.0
5
5
  - 2.1
6
6
  - 2.2
7
- - 2.3.0
8
- - 2.4.0
9
- - 2.5.0
10
- - 2.6.0
11
- - jruby-9.1.17.0
12
- - jruby-9.2.7.0
7
+ - 2.3
8
+ - 2.4
9
+ - 2.5
10
+ - 2.6
11
+ - 2.7
12
+ - 3.0
13
+ - jruby-9.2.9.0
13
14
  - ruby-head
14
15
  - jruby-head
15
16
 
@@ -19,9 +20,5 @@ matrix:
19
20
  - rvm: ruby-head
20
21
  - rvm: jruby-head
21
22
 
22
- before_install:
23
- - rvm all-gemsets do gem uninstall bundler -ax || true
24
- - gem install bundler -v "< 2"
25
-
26
23
  services:
27
24
  - redis-server
data/README.md CHANGED
@@ -1,10 +1,9 @@
1
1
  # Asynchronic
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/asynchronic.svg)](https://rubygems.org/gems/asynchronic)
4
- [![Build Status](https://travis-ci.org/gabynaiman/asynchronic.svg?branch=master)](https://travis-ci.org/gabynaiman/asynchronic)
4
+ [![Build Status](https://travis-ci.com/gabynaiman/asynchronic.svg?branch=master)](https://travis-ci.com/gabynaiman/asynchronic)
5
5
  [![Coverage Status](https://coveralls.io/repos/gabynaiman/asynchronic/badge.svg?branch=master)](https://coveralls.io/r/gabynaiman/asynchronic?branch=master)
6
6
  [![Code Climate](https://codeclimate.com/github/gabynaiman/asynchronic.svg)](https://codeclimate.com/github/gabynaiman/asynchronic)
7
- [![Dependency Status](https://gemnasium.com/gabynaiman/asynchronic.svg)](https://gemnasium.com/gabynaiman/asynchronic)
8
7
 
9
8
  DSL for asynchronic pipeline using queues over Redis
10
9
 
data/asynchronic.gemspec CHANGED
@@ -19,13 +19,12 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ['lib']
20
20
 
21
21
  spec.add_dependency 'ost', '~> 1.0'
22
- spec.add_dependency 'broadcaster', '~> 1.0'
22
+ spec.add_dependency 'broadcaster', '~> 1.0', '>= 1.0.2'
23
23
  spec.add_dependency 'class_config', '~> 0.0'
24
24
  spec.add_dependency 'transparent_proxy', '~> 0.0'
25
25
  spec.add_dependency 'multi_require', '~> 1.0'
26
26
 
27
- spec.add_development_dependency 'bundler', '~> 1.12'
28
- spec.add_development_dependency 'rake', '~> 11.0'
27
+ spec.add_development_dependency 'rake', '~> 12.0'
29
28
  spec.add_development_dependency 'minitest', '~> 5.0', '< 5.11'
30
29
  spec.add_development_dependency 'minitest-great_expectations', '~> 0.0'
31
30
  spec.add_development_dependency 'minitest-stub_any_instance', '~> 1.0'
data/lib/asynchronic.rb CHANGED
@@ -23,6 +23,8 @@ module Asynchronic
23
23
  attr_config :logger, Logger.new($stdout)
24
24
  attr_config :retry_timeout, 30
25
25
  attr_config :garbage_collector_timeout, 30
26
+ attr_config :redis_client, Redic
27
+ attr_config :redis_settings, 'redis://localhost:6379'
26
28
  attr_config :redis_data_store_sync_timeout, 0.01
27
29
  attr_config :keep_alive_timeout, 1
28
30
  attr_config :connection_name, "HOST=#{Socket.gethostname},PID=#{::Process.pid},UUID=#{SecureRandom.uuid}"
@@ -43,6 +45,12 @@ module Asynchronic
43
45
  @garbage_collector ||= GarbageCollector.new environment, garbage_collector_timeout
44
46
  end
45
47
 
48
+ def self.establish_redis_connection(options={})
49
+ redis_client = options.fetch(:redis_client, Asynchronic.redis_client)
50
+ redis_settings = options.fetch(:redis_settings, Asynchronic.redis_settings)
51
+ redis_client.new redis_settings
52
+ end
53
+
46
54
  def self.retry_execution(klass, message)
47
55
  begin
48
56
  result = yield
@@ -4,7 +4,15 @@ module Asynchronic
4
4
 
5
5
  include Helper
6
6
 
7
- def initialize(hash={})
7
+ def self.connect(object_id)
8
+ connections[object_id]
9
+ end
10
+
11
+ def self.connections
12
+ @connections ||= {}
13
+ end
14
+
15
+ def initialize
8
16
  @hash = {}
9
17
  @mutex = Mutex.new
10
18
  @keys_mutex = Hash.new { |h,k| h[k] = Mutex.new }
@@ -12,43 +20,37 @@ module Asynchronic
12
20
  end
13
21
 
14
22
  def [](key)
15
- Marshal.load(@hash[key.to_s]) if @hash.key? key.to_s
23
+ Marshal.load(hash[key.to_s]) if hash.key? key.to_s
16
24
  end
17
25
 
18
26
  def []=(key, value)
19
- @mutex.synchronize { @hash[key.to_s] = Marshal.dump(value) }
27
+ mutex.synchronize { hash[key.to_s] = Marshal.dump(value) }
20
28
  end
21
29
 
22
30
  def delete(key)
23
- @hash.delete key.to_s
31
+ hash.delete key.to_s
24
32
  end
25
33
 
26
34
  def delete_cascade(key)
27
- keys = self.keys.select { |k| k.sections.first == key }
28
- keys.each { |k| delete k }
35
+ keys.select { |k| k.sections.first == key }
36
+ .each { |k| delete k }
29
37
  end
30
38
 
31
39
  def keys
32
- @hash.keys.map { |k| Key[k] }
40
+ hash.keys.map { |k| Key[k] }
33
41
  end
34
42
 
35
43
  def synchronize(key, &block)
36
- @keys_mutex[key].synchronize(&block)
44
+ keys_mutex[key].synchronize(&block)
37
45
  end
38
46
 
39
47
  def connection_args
40
48
  [object_id]
41
49
  end
42
50
 
43
- def self.connect(object_id)
44
- connections[object_id]
45
- end
46
-
47
51
  private
48
52
 
49
- def self.connections
50
- @connections ||= {}
51
- end
53
+ attr_reader :hash, :mutex, :keys_mutex
52
54
 
53
55
  end
54
56
  end
@@ -1,19 +1,19 @@
1
1
  module Asynchronic
2
2
  module DataStore
3
3
  class Key < String
4
-
4
+
5
5
  SEPARATOR = '|'
6
6
 
7
7
  def self.[](key)
8
8
  new key
9
9
  end
10
-
10
+
11
11
  def initialize(key)
12
12
  super key.to_s
13
13
  end
14
14
 
15
15
  def [](key)
16
- self.class.new [self,key].join(SEPARATOR)
16
+ self.class.new [self, key].join(SEPARATOR)
17
17
  end
18
18
 
19
19
  def sections
@@ -14,11 +14,11 @@ module Asynchronic
14
14
  end
15
15
 
16
16
  def inspect
17
- "#<#{proxy_class} @data_store_class=#{@data_store_class} @data_store_connection_args=#{@data_store_connection_args} @key=#{@key}>"
17
+ "#<#{proxy_class} @data_store_class=#{data_store_class} @data_store_connection_args=#{data_store_connection_args} @key=#{key}>"
18
18
  end
19
19
 
20
20
  def data_store
21
- @data_store_class.connect(*@data_store_connection_args)
21
+ data_store_class.connect(*data_store_connection_args)
22
22
  end
23
23
 
24
24
  def to_value
@@ -27,8 +27,10 @@ module Asynchronic
27
27
 
28
28
  private
29
29
 
30
+ attr_reader :data_store_class, :data_store_connection_args, :key
31
+
30
32
  def __getobj__
31
- @value ||= data_store[@key]
33
+ @value ||= data_store[key]
32
34
  end
33
35
 
34
36
  end
@@ -6,13 +6,17 @@ module Asynchronic
6
6
 
7
7
  include Helper
8
8
 
9
- def initialize(scope, *args)
9
+ def self.connect(*args)
10
+ new(*args)
11
+ end
12
+
13
+ def initialize(scope, options={})
10
14
  @scope = Key[scope]
11
- @redis = Redic.new(*args)
15
+ @options = options
12
16
  end
13
17
 
14
18
  def [](key)
15
- value = @redis.call! 'GET', @scope[key]
19
+ value = redis.call! 'GET', scope[key]
16
20
  value ? Marshal.load(value) : nil
17
21
  rescue => ex
18
22
  Asynchronic.logger.warn('Asynchronic') { ex.message }
@@ -20,39 +24,43 @@ module Asynchronic
20
24
  end
21
25
 
22
26
  def []=(key, value)
23
- @redis.call! 'SET', @scope[key], Marshal.dump(value)
27
+ redis.call! 'SET', scope[key], Marshal.dump(value)
24
28
  end
25
29
 
26
30
  def delete(key)
27
- @redis.call! 'DEL', @scope[key]
31
+ redis.call! 'DEL', scope[key]
28
32
  end
29
33
 
30
34
  def delete_cascade(key)
31
- @redis.call! 'DEL', @scope[key]
32
- @redis.call!('KEYS', @scope[key]['*']).each { |k| @redis.call! 'DEL', k }
35
+ redis.call! 'DEL', scope[key]
36
+ redis.call!('KEYS', scope[key]['*']).each { |k| redis.call! 'DEL', k }
33
37
  end
34
38
 
35
39
  def keys
36
- @redis.call!('KEYS', @scope['*']).map { |k| Key[k].remove_first }
40
+ redis.call!('KEYS', scope['*']).map { |k| Key[k].remove_first }
37
41
  end
38
42
 
39
43
  def synchronize(key)
40
- while @redis.call!('GETSET', @scope[key][LOCKED], LOCKED) == LOCKED
44
+ while redis.call!('GETSET', scope[key][LOCKED], LOCKED) == LOCKED
41
45
  sleep Asynchronic.redis_data_store_sync_timeout
42
46
  end
43
47
  yield
44
48
  ensure
45
- @redis.call! 'DEL', @scope[key][LOCKED]
49
+ redis.call! 'DEL', scope[key][LOCKED]
46
50
  end
47
51
 
48
52
  def connection_args
49
- [@scope, @redis.url]
53
+ [scope, options]
50
54
  end
51
55
 
52
- def self.connect(*args)
53
- new(*args)
56
+ private
57
+
58
+ attr_reader :scope, :options
59
+
60
+ def redis
61
+ @redis ||= Asynchronic.establish_redis_connection options
54
62
  end
55
-
63
+
56
64
  end
57
65
  end
58
66
  end
@@ -4,34 +4,38 @@ module Asynchronic
4
4
 
5
5
  include Helper
6
6
 
7
- attr_reader :data_store
8
- attr_reader :scope
9
-
7
+ attr_reader :data_store, :scope
8
+
9
+ def self.connect(options)
10
+ data_store = options[:data_store_class].connect(*options[:data_store_connection_args])
11
+ new data_store, options[:scope]
12
+ end
13
+
10
14
  def initialize(data_store, scope)
11
15
  @data_store = data_store
12
16
  @scope = Key[scope]
13
17
  end
14
18
 
15
19
  def [](key)
16
- @data_store[@scope[key]]
20
+ data_store[scope[key]]
17
21
  end
18
22
 
19
23
  def []=(key, value)
20
- @data_store[@scope[key]] = value
24
+ data_store[scope[key]] = value
21
25
  end
22
26
 
23
27
  def delete(key)
24
- @data_store.delete @scope[key]
28
+ data_store.delete scope[key]
25
29
  end
26
30
 
27
31
  def delete_cascade
28
- @data_store.delete_cascade @scope
32
+ data_store.delete_cascade scope
29
33
  end
30
34
 
31
35
  def keys
32
- @data_store.keys.
33
- select { |k| k.start_with? @scope[''] }.
34
- map { |k| Key[k].remove_first @scope.sections.count }
36
+ data_store.keys
37
+ .select { |k| k.start_with? scope[''] }
38
+ .map { |k| Key[k].remove_first scope.sections.count }
35
39
  end
36
40
 
37
41
  def synchronize(key, &block)
@@ -41,20 +45,15 @@ module Asynchronic
41
45
  def connection_args
42
46
  [
43
47
  {
44
- data_store_class: @data_store.class,
45
- data_store_connection_args: @data_store.connection_args,
46
- scope: @scope
48
+ data_store_class: data_store.class,
49
+ data_store_connection_args: data_store.connection_args,
50
+ scope: scope
47
51
  }
48
52
  ]
49
53
  end
50
54
 
51
- def self.connect(*args)
52
- data_store = args[0][:data_store_class].connect *args[0][:data_store_connection_args]
53
- new data_store, args[0][:scope]
54
- end
55
-
56
55
  def to_s
57
- "#<#{self.class} @data_store=#{@data_store} @scope=#{@scope}>"
56
+ "#<#{self.class} @data_store=#{data_store} @scope=#{scope}>"
58
57
  end
59
58
 
60
59
  end
@@ -2,7 +2,7 @@ module Asynchronic
2
2
  class Environment
3
3
 
4
4
  attr_reader :queue_engine, :data_store, :notifier
5
-
5
+
6
6
  def initialize(queue_engine, data_store, notifier)
7
7
  @queue_engine = queue_engine
8
8
  @data_store = data_store
@@ -14,7 +14,7 @@ module Asynchronic
14
14
  end
15
15
 
16
16
  def default_queue
17
- queue(queue_engine.default_queue)
17
+ queue queue_engine.default_queue
18
18
  end
19
19
 
20
20
  def enqueue(msg, queue=nil)
@@ -28,7 +28,7 @@ module Asynchronic
28
28
  def load_process(id)
29
29
  Process.new self, id
30
30
  end
31
-
31
+
32
32
  def processes
33
33
  Process.all self
34
34
  end
@@ -1,9 +1,8 @@
1
1
  module Asynchronic
2
2
  class Error
3
3
 
4
- attr_reader :message
5
- attr_reader :backtrace
6
-
4
+ attr_reader :message, :backtrace
5
+
7
6
  def initialize(source)
8
7
  @message = source.respond_to?(:message) ? source.message : source.to_s
9
8
  @backtrace = source.respond_to?(:backtrace) ? source.backtrace : []
@@ -25,7 +25,8 @@ module Asynchronic
25
25
  begin
26
26
  processes.select(&condition).each(&:destroy)
27
27
  rescue => ex
28
- Asynchronic.logger.error('Asynchronic') { "#{ex.class}: #{ex.message}" }
28
+ error_message = "#{ex.class}: #{ex.message}\n#{ex.backtrace.join("\n")}"
29
+ Asynchronic.logger.error('Asynchronic') { error_message }
29
30
  end
30
31
  end
31
32
 
@@ -1,18 +1,6 @@
1
1
  module Asynchronic
2
2
  class Job
3
3
 
4
- def initialize(process)
5
- @process = process
6
- end
7
-
8
- def params
9
- @process.params
10
- end
11
-
12
- def result(reference)
13
- @process[reference].result
14
- end
15
-
16
4
  def self.queue(name=nil)
17
5
  name ? @queue = name : @queue
18
6
  end
@@ -23,6 +11,18 @@ module Asynchronic
23
11
  process.id
24
12
  end
25
13
 
14
+ def initialize(process)
15
+ @process = process
16
+ end
17
+
18
+ def params
19
+ process.params
20
+ end
21
+
22
+ def result(reference)
23
+ process[reference].result
24
+ end
25
+
26
26
  private
27
27
 
28
28
  attr_reader :process