j_future 0.0.1-java

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d3b8dbfabd5a6e294509d71902e15bce2bf06177
4
+ data.tar.gz: 8d8fc608cb785e0ebfa1f119bac804b184def594
5
+ SHA512:
6
+ metadata.gz: b63fdccd5b652bc3b7f96200bb071bebfbd856cf3d8411e455c168a23b6e2f7c6501cef840f0ac3dacc3221be168dfd248d190bc7ed2b2f3850828510a329960
7
+ data.tar.gz: a6ae8f5245ef4dd7b3a1a601b887211fa08eb427378d7f3ede7bb186a311d86ed514683a3f5894a8933c237337686f5cf1a6c657c99eec25f0d4d47e55f2ee00
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ future
2
+ ======
3
+
4
+ A seemless proxy future object framework for jruby to do work in parallel
5
+
6
+ Usage
7
+ -----
8
+
9
+ First, create a thread pool executor to execute the tasks. Ideally this should be done in the application initializer.
10
+ ``` ruby
11
+ executor = JFuture::ExecutorFactory.create
12
+ ```
13
+
14
+ Its is recommended that you give a name for the executor (default name is `:default`). Below we create a thread pool executor with all available options:
15
+ ``` ruby
16
+ executor = JFuture::ExecutorFactory.create(name: :my_pool)
17
+ ```
18
+
19
+ Let us pick some calls and make them concurrent
20
+ ``` ruby
21
+ people = Person.all # call to database
22
+ people.do_something # use result by calling methods on it
23
+ cars = Car.all # call to database
24
+ cars.do_something # use result by calling methods on it
25
+ ```
26
+ change the above to execute in parallel:
27
+ ``` ruby
28
+ people = JFuture.new(executor: :my_pool) { Person.all } # makes async call to database and returns the result as a future object
29
+ cars = JFuture.new(executor: :my_pool) { Car.all } # makes async call to database and returns the result as a future object
30
+ people.do_something # waits on the future object to be popluated and only then is the method call executed
31
+ cars.do_something # waits on the future object to be popluated and only then is the method call executed
32
+ ```
33
+
34
+
35
+ ExecutorFactory options with defaults
36
+ -------------------------------------
37
+ ``` ruby
38
+ executor = JFuture::ExecutorFactory.create(core_pool_size: 20,
39
+ max_pool_size: 20,
40
+ keep_alive_millis: 120000,
41
+ queue_size: 10,
42
+ name: :default,
43
+ thread_factory: DaemonThreadFactory.new)
44
+ ```
45
+
46
+ Submit task to an executor
47
+ --------------------------
48
+ ```JFuture.new``` can take either the name of executor or a reference to an executor
49
+ ``` ruby
50
+ people = JFuture.new(executor: :my_pool) { Person.all }
51
+ ```
52
+ or
53
+ ``` ruby
54
+ people = JFuture.new(executor: executor) { Person.all }
55
+ ```
56
+ Timeouts
57
+ --------
58
+ Read access timeout on future object can be set as:
59
+ ``` ruby
60
+ people = JFuture.new(executor: executor, access_timeout_millis: 100) { Person.all }
61
+ people.do_something # timer is triggered on access
62
+ ```
63
+ on timeout throws exception:
64
+ ``` ruby
65
+ Java::JavaUtilConcurrent::TimeoutException
66
+ ```
67
+ is_done? check
68
+ --------------
69
+ Check if the future is populated without blocking on it(any method other than is_done? is guranteed to block)
70
+ ``` ruby
71
+ people.is_done? # true / false
72
+ ```
73
+
74
+ Async callbacks on future completion:
75
+ -------------------------------------
76
+ ``` ruby
77
+ restaurant = JFuture.new {Restaurant.find(id)} # get future object
78
+ restaurant.on_complete {|restaurant| puts restaurant.name} # set up an async callback
79
+ ```
80
+ by chaining:
81
+ ``` ruby
82
+ JFuture.new {Restaurant.find(id)}.on_complete {|result| puts result.name}
83
+ ```
84
+ The timeout on future applies to the on_complete as well. It will throw a Java::JavaUtilConcurrent::TimeoutException on time out. This error can be handled by adding a rescue block for the error inside on_complete block.
85
+ ``` ruby
86
+ JFuture.new(access_timeout_millis: 1) {Restaurant.find(id)}.on_complete do
87
+ begin
88
+ puts restaurant.name
89
+ rescue Java::JavaUtilConcurrent::TimeoutException
90
+ puts 'task timed out'
91
+ end
92
+ end
93
+ ```
94
+ Note:
95
+ -----
96
+ The `access_timeout_millis` only applies to the thread blocking on future object. the worker thread which computes the future will be blocked for as long as it takes to compute the future object without any timeout applicable to it. So, only pass things into future that will complete.
97
+ The callback and future object computation are scheduled as separate tasks possibly taking up different threads. While deciding the number of workers for the executor keep in mind that blocked task with callback results in two blocked workers.
98
+
data/j_future.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require "./lib/j_future/version"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'j_future'
6
+ s.version = JFuture::VERSION
7
+ s.platform = 'java'
8
+ s.authors = ['Sumanth K N']
9
+ s.email = ['kn.sumanth@gmail.com']
10
+ s.homepage = 'https://github.com/kn-sumanth/j_future'
11
+ s.description = s.summary = %q{simple future object framework for jruby}
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.require_paths = ['lib']
17
+ s.license = 'MIT'
18
+ s.add_development_dependency 'bundler'
19
+ s.add_development_dependency 'minitest', '>= 5.0.0'
20
+ s.add_development_dependency 'rake'
21
+ end
@@ -0,0 +1,12 @@
1
+ class JFuture < ::BasicObject
2
+ class Callable
3
+ include Java::JavaUtilConcurrent::Callable
4
+ def initialize(arg = nil, &block)
5
+ @block = block
6
+ @arg = arg
7
+ end
8
+ def call
9
+ @block.call @arg
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ class JFuture < ::BasicObject
2
+ class DaemonThreadFactory
3
+ include Java::JavaUtilConcurrent::ThreadFactory
4
+ def newThread(runnable)
5
+ thread = Java::JavaUtilConcurrent::Executors.defaultThreadFactory().newThread(runnable)
6
+ thread.setDaemon(true)
7
+ thread
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,28 @@
1
+ class JFuture < ::BasicObject
2
+ class ExecutorFactory
3
+ @@executor_map = {}
4
+ def self.create(core_pool_size: 20,
5
+ max_pool_size: 20,
6
+ keep_alive_millis: 120000,
7
+ queue_size: 10,
8
+ name: :default,
9
+ thread_factory: DaemonThreadFactory.new)
10
+
11
+ work_queue = queue_size.to_i > 0 ?
12
+ Java::JavaUtilConcurrent::LinkedBlockingQueue.new(queue_size.to_i) :
13
+ Java::JavaUtilConcurrent::SynchronousQueue.new
14
+ executor = Java::JavaUtilConcurrent::ThreadPoolExecutor.new(
15
+ core_pool_size.to_i,
16
+ max_pool_size.to_i,
17
+ keep_alive_millis.to_i,
18
+ MILLIS,
19
+ work_queue,
20
+ thread_factory)
21
+ @@executor_map[name] = executor
22
+ end
23
+
24
+ def self.get_executor(name = :default)
25
+ @@executor_map[name]
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ class JFuture < ::BasicObject
2
+ VERSION = "0.0.1"
3
+ end
data/lib/j_future.rb ADDED
@@ -0,0 +1,46 @@
1
+ require 'java'
2
+ require_relative 'j_future/version'
3
+ require_relative 'j_future/callable'
4
+ require_relative 'j_future/daemon_thread_factory'
5
+ require_relative 'j_future/executor_factory'
6
+ class JFuture < ::BasicObject
7
+ MILLIS = ::Java::JavaUtilConcurrent::TimeUnit::MILLISECONDS
8
+ METHODS = [:is_done?, :on_complete]
9
+
10
+ def initialize(executor: :default, access_timeout_millis: nil, &block)
11
+ @access_timeout_millis = access_timeout_millis
12
+ callable = Callable.new(&block)
13
+ if (executor.is_a? ::Java::JavaUtilConcurrent::AbstractExecutorService)
14
+ @executor = executor
15
+ else
16
+ @executor = ExecutorFactory.get_executor(executor)
17
+ end
18
+ @future = @executor.submit callable
19
+ end
20
+
21
+ def respond_to?(id, *args)
22
+ return true if METHODS.include?(id)
23
+ if @access_timeout_millis.nil?
24
+ @future.get.respond_to?(id, *args)
25
+ else
26
+ @future.get(@access_timeout_millis.to_i, MILLIS).respond_to?(id, *args)
27
+ end
28
+ end
29
+
30
+ def is_done?
31
+ @future.isDone
32
+ end
33
+
34
+ def on_complete(&block)
35
+ callback = Callable.new(self, &block)
36
+ @executor.submit callback
37
+ end
38
+
39
+ def method_missing(name, *args, &block)
40
+ if @access_timeout_millis.nil?
41
+ @future.get.send(name, *args, &block)
42
+ else
43
+ @future.get(@access_timeout_millis.to_i, MILLIS).send(name, *args, &block)
44
+ end
45
+ end
46
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: j_future
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: java
6
+ authors:
7
+ - Sumanth K N
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-02-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ name: bundler
20
+ prerelease: false
21
+ type: :development
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 5.0.0
33
+ name: minitest
34
+ prerelease: false
35
+ type: :development
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 5.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ name: rake
48
+ prerelease: false
49
+ type: :development
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: simple future object framework for jruby
56
+ email:
57
+ - kn.sumanth@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - README.md
65
+ - j_future.gemspec
66
+ - lib/j_future.rb
67
+ - lib/j_future/callable.rb
68
+ - lib/j_future/daemon_thread_factory.rb
69
+ - lib/j_future/executor_factory.rb
70
+ - lib/j_future/version.rb
71
+ homepage: https://github.com/kn-sumanth/j_future
72
+ licenses:
73
+ - MIT
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 2.4.8
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: simple future object framework for jruby
95
+ test_files: []