Skip to content
This repository has been archived by the owner on Aug 23, 2024. It is now read-only.

Commit

Permalink
Migrate to suspendCommand and suspendCommandAsync to be more clear wh…
Browse files Browse the repository at this point in the history
…ich operation is taking place
  • Loading branch information
bradynpoulsen committed Dec 21, 2018
1 parent 5c6e641 commit 8c3022c
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 79 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ Provides coroutine builders to execute AWS Java SDK commands as asynchronous or
## Example

```kotlin
val asyncClient = getAwsEc2AsyncClient()
val client: AmazonEC2 = buildAmazonEC2Client()

// Launch a new instance for every custom AMI in the current account
coroutineScope {
with(CoroutineScope(Dispatchers.IO + Job())) {
// suspends until the SDK command has completed
awsCoroutine(asyncClient::describeImagesAsync) {
suspendCommand(client::describeImages) {
DescribeImagesRequest()
.withOwners("self")
}.images.map { image ->
// launch SDK commands in parallel
async {
awsCoroutine(asyncClient::runInstancesAsync) {
suspendCommand(client::runInstances) {
RunInstancesRequest(image.imageId, 1, 1)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.github.bradynpoulsen.aws.coroutines
import com.amazonaws.AmazonWebServiceRequest
import com.amazonaws.AmazonWebServiceResult
import com.amazonaws.handlers.AsyncHandler
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.cancelFutureOnCancellation
import kotlinx.coroutines.suspendCancellableCoroutine
import java.util.concurrent.Future
Expand All @@ -11,31 +12,45 @@ import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException

/**
* Starts a cancellable coroutine that executes [method] and responds with the [AwsResult].
* Starts a [CancellableContinuation] that executes [method] and resumes with the [AwsResult].
*
* _Note_: This request is launched in the SDK client's executor threads.
* See [com.amazonaws.client.builder.AwsAsyncClientBuilder.AsyncBuilderParams.defaultExecutor] for more details.
*
* Example:
*
* val client: AmazonEC2Async = buildClient()
* val describeResult: DescribeInstancesResult = awsCoroutine(client::describeInstancesAsync)
* val describeResult: DescribeInstancesResult = suspendCommandAsync(client::describeInstancesAsync)
*/
@ExperimentalAwsCoroutineApi
suspend inline fun <AwsRequest : AmazonWebServiceRequest, AwsResult : AmazonWebServiceResult<*>> awsCoroutine(
crossinline method: (request: AwsRequest, handler: AsyncHandler<AwsRequest, AwsResult>) -> Future<AwsResult>,
crossinline requestBuilder: () -> AwsRequest
suspend inline fun <AwsRequest : AmazonWebServiceRequest, AwsResult : AmazonWebServiceResult<*>> suspendCommandAsync(
crossinline method: (handler: AsyncHandler<AwsRequest, AwsResult>) -> Future<AwsResult>
): AwsResult = suspendCancellableCoroutine {
method(requestBuilder(), AwsContinuationAsyncHandler(it)).also { future ->
method(AwsContinuationAsyncHandler(it)).also { future ->
it.cancelFutureOnCancellation(future)
}
}

/**
* Starts a cancellable coroutine that executes [method] and responds with the [AwsResult].
* Starts a [CancellableContinuation] that executes [method] and resumes with the [AwsResult].
*
* _Note_: This request is launched in the SDK client's executor threads.
* See [com.amazonaws.client.builder.AwsAsyncClientBuilder.AsyncBuilderParams.defaultExecutor] for more details.
*
* Example:
*
* val client: AmazonEC2Async = buildClient()
* val describeResult: DescribeImagesResult = suspendCommandAsync(client::describeImagesAsync) {
* DescribeImagesRequest()
* .withImageIds("ami-12312412431754", "ami-12334237461523")
* }
*/
@ExperimentalAwsCoroutineApi
suspend inline fun <AwsRequest : AmazonWebServiceRequest, AwsResult : AmazonWebServiceResult<*>> awsCoroutine(
crossinline method: (handler: AsyncHandler<AwsRequest, AwsResult>) -> Future<AwsResult>
suspend inline fun <AwsRequest : AmazonWebServiceRequest, AwsResult : AmazonWebServiceResult<*>> suspendCommandAsync(
crossinline method: (request: AwsRequest, handler: AsyncHandler<AwsRequest, AwsResult>) -> Future<AwsResult>,
crossinline requestBuilder: () -> AwsRequest
): AwsResult = suspendCancellableCoroutine {
method(AwsContinuationAsyncHandler(it)).also { future ->
method(requestBuilder(), AwsContinuationAsyncHandler(it)).also { future ->
it.cancelFutureOnCancellation(future)
}
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.github.bradynpoulsen.aws.coroutines

import com.amazonaws.AmazonWebServiceRequest
import com.amazonaws.AmazonWebServiceResult
import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext

/**
* Executes the synchronous [method] in the current [CoroutineScope]'s dispatcher.
*
* Example:
*
* val client: AmazonEC2 = buildClient()
* val describeResult: DescribeInstancesResult = suspendCommand(client::describeInstances)
*/
@ExperimentalAwsCoroutineApi
@UseExperimental(ExperimentalCoroutinesApi::class)
suspend inline fun <AwsResult : AmazonWebServiceResult<*>> CoroutineScope.suspendCommand(
crossinline method: () -> AwsResult,
context: CoroutineContext = EmptyCoroutineContext
): AwsResult = withContext(newCoroutineContext(context)) {
method()
}

/**
* Executes the synchronous [method] in the current [CoroutineScope]'s dispatcher.
*
* Example:
*
* val client: AmazonEC2 = buildClient()
* val describeResult: DescribeImagesResult = suspendCommand(client::describeImages) {
* DescribeImagesRequest()
* .withImageIds("ami-12312412431754", "ami-12334237461523")
* }
*/
@ExperimentalAwsCoroutineApi
@UseExperimental(ExperimentalCoroutinesApi::class)
suspend inline fun <AwsRequest : AmazonWebServiceRequest, AwsResult : AmazonWebServiceResult<*>> CoroutineScope.suspendCommand(
crossinline method: (request: AwsRequest) -> AwsResult,
context: CoroutineContext = EmptyCoroutineContext,
crossinline requestBuilder: () -> AwsRequest
): AwsResult = withContext(newCoroutineContext(context)) {
method(requestBuilder())
}
12 changes: 7 additions & 5 deletions java-sdk/src/test/kotlin/example/async.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package example

import com.amazonaws.services.ec2.AmazonEC2Async
import com.amazonaws.services.ec2.model.*
import com.github.bradynpoulsen.aws.coroutines.awsCoroutine
import com.amazonaws.services.ec2.model.AmazonEC2Exception
import com.amazonaws.services.ec2.model.DescribeReservedInstancesResult
import com.amazonaws.services.ec2.model.RebootInstancesRequest
import com.github.bradynpoulsen.aws.coroutines.suspendCommandAsync

val asyncClient: AmazonEC2Async = TODO()
val ec2AsyncClient: AmazonEC2Async = TODO()

private suspend fun exampleAsync() {
val result: DescribeReservedInstancesResult = awsCoroutine(asyncClient::describeReservedInstancesAsync)
val result: DescribeReservedInstancesResult = suspendCommandAsync(ec2AsyncClient::describeReservedInstancesAsync)

result.reservedInstances.forEach {
println("${it.reservedInstancesId}: ${it.start..it.end} ${it.availabilityZone}")
Expand All @@ -16,7 +18,7 @@ private suspend fun exampleAsync() {

private suspend fun exampleAsyncWithRequestBuilder() {
try {
awsCoroutine(asyncClient::rebootInstancesAsync) {
suspendCommandAsync(ec2AsyncClient::rebootInstancesAsync) {
RebootInstancesRequest()
.withInstanceIds("i-09593e1eca1212a29")
}
Expand Down
29 changes: 0 additions & 29 deletions java-sdk/src/test/kotlin/example/blocking.kt

This file was deleted.

28 changes: 28 additions & 0 deletions java-sdk/src/test/kotlin/example/sync.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package example

import com.amazonaws.services.ec2.AmazonEC2
import com.amazonaws.services.ec2.model.DescribeImagesRequest
import com.github.bradynpoulsen.aws.coroutines.suspendCommand
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope

val ec2Client: AmazonEC2 = TODO()

private suspend fun exampleBlocking() = coroutineScope {
val result = suspendCommand(ec2Client::describeReservedInstances)

result.reservedInstances.forEach {
println("${it.reservedInstancesId}: ${it.start..it.end} ${it.availabilityZone}")
}
}

private suspend fun exampleBlockingWithRequestBuilder() = coroutineScope {
val result = suspendCommand(ec2Client::describeImages, context = Dispatchers.IO) {
DescribeImagesRequest()
.withImageIds("ami-12312412431754", "ami-12334237461523")
}

result.images.forEach {
println("${it.imageId}: ${it.description}")
}
}

0 comments on commit 8c3022c

Please sign in to comment.