Skip to content

Commit

Permalink
Merge branch 'release/v3.0.0-rc.1036'
Browse files Browse the repository at this point in the history
  • Loading branch information
mplatvoet committed Feb 4, 2016
2 parents f4e89ff + 9aa4f62 commit 6d88e46
Show file tree
Hide file tree
Showing 86 changed files with 833 additions and 691 deletions.
File renamed without changes.
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
[![CircleCI branch](https://img.shields.io/circleci/project/mplatvoet/kovenant/master.svg)](https://circleci.com/gh/mplatvoet/kovenant/tree/master) [![Maven Central](https://img.shields.io/maven-central/v/nl.komponents.kovenant/kovenant.svg)](http://search.maven.org/#browse%7C1069530195) [![DUB](https://img.shields.io/dub/l/vibe-d.svg)](https://github.com/mplatvoet/kovenant/blob/master/LICENSE)
[![CircleCI branch](https://img.shields.io/circleci/project/mplatvoet/kovenant/master.svg)](https://circleci.com/gh/mplatvoet/kovenant/tree/master) [![Maven Central](https://img.shields.io/maven-central/v/nl.komponents.kovenant/kovenant.svg)](http://search.maven.org/#browse%7C1069530195) [![DUB](https://img.shields.io/dub/l/vibe-d.svg)](https://github.com/mplatvoet/kovenant/blob/master/LICENSE.txt)
develop: [![Develop dependency status](https://www.versioneye.com/user/projects/55b088c23865620018000203/badge.svg?style=flat)](https://www.versioneye.com/user/projects/55b088c23865620018000203)
master: [![Master dependency status](https://www.versioneye.com/user/projects/55b088d23865620017000296/badge.svg?style=flat)](https://www.versioneye.com/user/projects/55b088d23865620017000296)


#Kovenant
[Promises](http://en.wikipedia.org/wiki/Futures_and_promises) for [Kotlin](http://kotlinlang.org).

The easy asynchronous library for Kotlin. With extensions for Android, LMAX Disruptor, JavaFX and much more.

```kt
async { "world" } and async { "Hello" } success {
task { "world" } and task { "Hello" } success {
println("${it.second} ${it.first}!")
}
```

Please refer to the [Kovenant](http://kovenant.komponents.nl) site for API usage and more.

## Getting started
This version is build against `kotlin-stdlib:1.0.0-beta-1038`.
Build against Kotlin 1.0 rc: `1.0.0-rc-1036`.
Source and target compatibility is `1.6`

###Gradle
```groovy
dependencies {
compile 'nl.komponents.kovenant:kovenant:3.0.+'
compile 'nl.komponents.kovenant:kovenant:3.0.0-rc.1036'
}
```

Expand All @@ -29,7 +32,7 @@ dependencies {
<dependency>
<groupId>nl.komponents.kovenant</groupId>
<artifactId>kovenant</artifactId>
<version>[3.0.0,3.1.0)</version>
<version>3.0.0-rc.1036</version>
</dependency>
```

Expand Down Expand Up @@ -58,6 +61,9 @@ Issues are tracked in [Youtrack](http://issues.komponents.nl/youtrack/issues?q=p
##Release notes
See [Changelog](http://kovenant.komponents.nl/changelog/) for release notes

##Slack
Join the `#kovenant` channel on [Kotlin Slack](http://kotlinslackin.herokuapp.com).

## Recommended libraries:
Other libraries for Kotlin applications

Expand Down
7 changes: 4 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
*/

buildscript {
ext.kotlinVersion = '1.0.0-beta-1038'
ext.kotlinVersion = '1.0.0-rc-1036'
ext.extraConfVersion = '2.2.+'

repositories {
Expand All @@ -38,7 +38,7 @@ buildscript {

allprojects {
ext {
appVersion = '3.0.0'
appVersion = '3.0.0-rc.1036'
appGroup = 'nl.komponents.kovenant'


Expand Down Expand Up @@ -79,6 +79,7 @@ subprojects {
compile "org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}", optional

testCompile "junit:junit:${junitVersion}"
testCompile "org.jetbrains.kotlin:kotlin-test:${kotlinVersion}"
}


Expand Down Expand Up @@ -206,7 +207,7 @@ task release() {
}

task wrapper(type: Wrapper) {
gradleVersion = '2.8'
gradleVersion = '2.10'

doLast() {
def gradleOpts = "-XX:MaxMetaspaceSize=1024m -Xmx1024m"
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/addons/progress.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ control.progress.update {
}

val steps = 40
async {
task {
for (i in 1..steps ) {
control.value = i / steps.toDouble()
Thread.sleep(100)
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/addons/ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ library provides `successUi`, `failUi` and `alwaysUi`. They operate just like th
callbacks can be mixed freely.

```kt
val promise = async {
val promise = task {
foo() //produces 'bar'
}

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/android/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ callbacks can be mixed freely. If a callback is added to an already resolved `Pr
without scheduling. If you want to force scheduling just pas `alwaysSchedule = true` along.

```kt
val promise = async {
val promise = task {
foo() //produces 'bar'
}

Expand Down
6 changes: 3 additions & 3 deletions docs/docs/api/combine_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ promise fail.


```kt
val fib20Promise = async { fib(20) }
val helloWorldPromise = async { "hello world" }
val fib20Promise = task { fib(20) }
val helloWorldPromise = task { "hello world" }

combine(fib20Promise, helloWorldPromise) success {
val (fib, msg) = it
Expand All @@ -23,7 +23,7 @@ combine(fib20Promise, helloWorldPromise) success {
For the special case of `combine` with only two parameters there is also an extension method `and` available. This
simply creates nicer looking code and plays well with conciseness fetishists:
```kt
async { fib(20) } and async { "hello world" } success {
task { fib(20) } and task { "hello world" } success {
println("${it.second}, fib(20) = ${it.first}")
}
```
12 changes: 6 additions & 6 deletions docs/docs/api/core_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The `Context` object is basically the current configuration. It can be obtained
by `Kovenant.context {...}`. Refer to the [configuration](#configuration) section for the options. To create
a completely new `Context` just use `Kovenant.createContext {...}` which uses the exact same options as `Kovenant.context {...}`.

Functions like [`deferred`](core_usage.md#deferred) and [`async`](core_usage.md#async) have a first parameter which
Functions like [`deferred`](core_usage.md#deferred) and [`task`](core_usage.md#task) have a first parameter which
is actually a `Context` instance. By default this is `Kovenant.context` so normally you don't have worry about this.
Just for that case you want to work with multiple configurations at once you have the possibility.

Expand All @@ -20,14 +20,14 @@ fun main(args: Array<String>) {
workerContext.dispatcher = buildDispatcher { name = "work-new" }
}

async {
println("default async $threadName")
task {
println("default task $threadName")
} success {
println("default success $threadName")
}

async(ctx) {
println("ctx async $threadName")
task(ctx) {
println("ctx task $threadName")
} success {
println("ctx success $threadName")
}
Expand Down Expand Up @@ -140,7 +140,7 @@ Kovenant.context {
Kovenant.context {
// Specify a new worker dispatcher.
// this dispatcher is responsible for
// work that is executed by async and
// work that is executed by `task` and
// then functions so this is basically
// work that is expected to run a bit
// longer
Expand Down
38 changes: 19 additions & 19 deletions docs/docs/api/core_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,21 @@ part of [`kovenant-core`](../index.md#artifacts)

---

##Async
The easiest way to create a `Promise` is by using `async`, e.g.
##Task
The easiest way to create a `Promise` is by using `task`, e.g.
```kt
val promise = async { foo() }
val promise = task { foo() }
```
This will execute function `foo()` asynchronously and immediately returns a `Promise<V, Exception>` where `V` is
the inferred return type of `foo()`. If `foo()` completes successful the `Promise` is resolved as successful. Any
`Exception` from `foo()` is considered a failure.

`async` dispatches the work on the [`workerContext`](core_config.md).
`task` dispatches the work on the [`workerContext`](core_config.md).

---

##Deferred
With a `Deferred<V,E>` you can take matters in your own hand. Instead of relying on [`async`](#async) for resolving
With a `Deferred<V,E>` you can take matters in your own hand. Instead of relying on [`task`](#task) for resolving
or rejecting a promise it's up to the developer. You obtain a deferred object by simply calling `deferred<V, E>()`.
From there you can either `resolve(V)` or `reject(E)` the deferred. This can only be set once and by default trying
to resolve or reject multiple times throws an Exception. The behaviour can be [configured](core_config.md) though.
Expand Down Expand Up @@ -63,7 +63,7 @@ No matter what the result of the promise is, success or failure, `always` get fi
[*Please read the extra note on the order of calling `success`, `fail` and `always`.*](#execution-order)

```kt
val promise = async {
val promise = task {
//mimicking those long running operations with:
1 + 1
}
Expand All @@ -87,7 +87,7 @@ promise always {
All callback registering functions return `this` Promise, thus previous example can be written without those intermediate variables

```kt
async {
task {
//some (long running) operation, or just:
1 + 1
} success {
Expand All @@ -108,7 +108,7 @@ But you can also provide your own DispatcherContext for a specific callback.
```kt
val dispatcherContext = //...

async {
task {
foo()
}.success(dispatcherContext) {
bar()
Expand All @@ -123,7 +123,7 @@ Thus a promise can be passed around and anybody who's interested can get notifie
Every callback will be called once and only once upon completion.

```kt
async {
task {
1 + 1
} success {
println("1")
Expand All @@ -147,10 +147,10 @@ The default behaviour can easily be broken though. For instance, if you configur
val firstRef = AtomicReference<String>()
val secondRef = AtomicReference<String>()

val first = async { "hello" } success {
val first = task { "hello" } success {
firstRef.set(it)
}
val second = async { "world" } success {
val second = task { "world" } success {
secondRef.set(it)
}

Expand All @@ -167,11 +167,11 @@ So don't just blindly change the callback `DispatcherContext` without actually u
---

##Then
`then` operates similar to [`async`](#async) except that it takes the output from a previous `Promise` as its input.
`then` operates similar to [`task`](#task) except that it takes the output from a previous `Promise` as its input.
This allows you to chain units of work.

```kt
async {
task {
fib(20)
} then {
"fib(20) = $it, and fib(21) = (${fib(21)})"
Expand All @@ -189,7 +189,7 @@ failed. The work of `then` is executed by the `workerContext`.
as an extension function. The previous example would thus be:

```kt
async {
task {
fib(20)
} thenUse {
"fib(20) = $this, and fib(21) = (${fib(21)})"
Expand All @@ -207,7 +207,7 @@ If the error value of the promise is an Exception then that is thrown directly,
with the error value wrapped in it.

```kt
val fib20 : Int = async { fib(20) }.get()
val fib20 : Int = task { fib(20) }.get()
```
>Note that implementors should override this function because the fallback methods are far from efficient
Expand All @@ -224,7 +224,7 @@ it is successful or has failed. This comes in handy in combination with `get()`.

##Lazy Promise
Kovenant provides a `lazyPromise` property delegate similar to Kotlin's standard library `Delegates.lazy {}`.
The difference with the standard library version is that initialization happens by an [`async`](#async) operation and
The difference with the standard library version is that initialization happens by an [`task`](#task) operation and
thus effectively on a background thread. This is particularly useful on platforms like Android where you want to avoid
initialization on the UI Thread.

Expand Down Expand Up @@ -282,7 +282,7 @@ you can set `cancelOthersOnFail = false`. See [cancel](#cancel) for more on this

```kt
val promises = Array(10) { n ->
async {
task {
Pair(n, fib(n))
}
}
Expand All @@ -308,7 +308,7 @@ you can set `cancelOthersOnSuccess = false`. See [cancel](#cancel) for more on t

```kt
val promises = Array(10) { n ->
async {
task {
while(!Thread.currentThread().isInterrupted()) {
val luckyNumber = Random(System.currentTimeMillis() * n).nextInt(100)
if (luckyNumber == 7) break
Expand All @@ -332,7 +332,7 @@ any (*promises) success { msg ->

##Cancel
Any `Promise` that implements `CancelablePromise` allows itself to be cancelled. By default the promises returned
from [`async`](#async), [`then`](#then) and [`thenUse`](#thenUse) are `CancelablePromise`s.
from [`task`](#task), [`then`](#then) and [`thenUse`](#thenUse) are `CancelablePromise`s.

Cancelling a promises is quite similar to [`Deferred.reject`](#deferred) as it finishes the promises as failed. Thus
the callbacks `fail` and `always` are still executed. Cancel does also try to prevent the promised work from ever being
Expand Down
49 changes: 42 additions & 7 deletions docs/docs/api/jvm_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ part of [`kovenant-jvm`](../index.md#artifacts)
##Executors

It's likely that your project already uses threadpools or that you want to leverage the threadpool
Kovenant uses. Because to many threads just leads to context switching and thus performance degradation.
Therefor Kovenant provides some facilities for interoperability with Java's Executors.
Kovenant uses. Because too many threads just leads to context switching and thus performance degradation.
Therefore Kovenant provides some facilities for interoperability with Java's Executors.

* To convert Kovenant's `Dispatcher`s to Java's `Executor` use the extension function `asExecutor()`
* To convert Kovenant's `Dispatcher`s to Java's `ExecutorService` use the extension function `asExecutorService()`
Expand Down Expand Up @@ -44,12 +44,47 @@ private class FibCallable(private val n: Int) : Callable<Pair<Int, Int>> {
---

##Throttle
There are case where finer control of the number of parallel tasks is needed, for instance when some specific type of task uses vast amounts of memory. This is what a `Throttle` is for. It allows you to limit the number of parallel task completely independent of any underlying `Dispatcher`. So no matter on what `Context` and thus `Dispatcher` your async tasks run, it's always within bounds.

There are cases where you want to control the number of parallel tasks in certain parts of your application, but not all.
For instance when some tasks use up large amounts of memory. This is where a `Throttle` comes in to play. With a
`Throttle` you're able to configure how many tasks are allowed to run in parallel. A `Throttle` can be used over
multiple existing Dispatchers, so you don't have to worry on which context Promises run.
You create a `Throttle` instance simply calling its constructor with any positive number indicating the maximum number of concurrent tasks:

```kotlin
// a Throttle with 2 parallel tasks at max
val myThrottle = Throttle(2)
```

Optionally you can provide the `Context` on which new async tasks are run on by default. The can always be overridden per specific task.

```kotlin
//configure with myContext
//the default is Kovenant.context
val myThrottle = Throttle(2, myContext)
```

###simple tasks
The easiest way to use a `Throttle` instance is by using the `task` method. This creates a task similar to the general `task` method that gets scheduled somewhere in the future. The result is, of course, a `Promise`

```kotlin
myThrottle.task {
foo()
} always {
println("done")
}
```

###manual registering
Sometimes you want to throttle a whole chain of promises. So you need to manually register the start and end of the chain. The `registerTask` and `registerDone` gives you that freedom. It's up to you to make sure that every `registerTask` is balanced with a countering `registerDone`. Failing to do so may either result in more than the configured tasks to run parallel or simply a deadlock.

```kotlin
val promise = myThrottle.registerTask { foo() }

//the rest of the chain
val lastPromise = promise then { bar() } then { baz() }

myThrottle.registerDone(lastPromise)
```

###Full Throttle example
```kt
fun main(args: Array<String>) {
Kovenant.context {
Expand Down Expand Up @@ -88,4 +123,4 @@ fun main(args: Array<String>) {
println("all tasks created")
}
```


Loading

0 comments on commit 6d88e46

Please sign in to comment.