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 +7 -0
- data/.gitignore +5 -0
- data/Gemfile +3 -0
- data/README.md +98 -0
- data/j_future.gemspec +21 -0
- data/lib/j_future/callable.rb +12 -0
- data/lib/j_future/daemon_thread_factory.rb +10 -0
- data/lib/j_future/executor_factory.rb +28 -0
- data/lib/j_future/version.rb +3 -0
- data/lib/j_future.rb +46 -0
- metadata +95 -0
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/Gemfile
ADDED
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,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
|
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: []
|