Giter Club home page Giter Club logo

aws-sdk's Introduction

Use AWS SDK v2 with Vert.x

Build Status

This project provides a VertxNioAsyncHttpClient and a VertxExecutor so that you can use AWS SDK v2 in a Vert.x context.

Coordinates

Artifacts are published here

Version compatibility matrix

Project Vert.x AWS sdk
1.2.2 4.4.5 2.20.138
1.2.1 4.4.2 2.20.74
1.2.0 4.4.0 2.20.2
1.1.0 4.2.4 2.17.129
1.0.0 4.0.0 2.15.45
0.7.0 3.9.4 2.15.23
0.6.0 3.9.2 2.14.7
0.5.1 3.9.2 2.13.6
0.5.0 3.9.0 2.12.0
0.4.0 3.8.3 2.10.16
0.3.0 3.8.1 2.7.8

Documentation

See this page

Motivations

AWS SDK v1 => blocking IOs

As you know, Vert.x uses non-blocking IO. This means, among other stuff, that you should never ever block the event-loop. AWS SDK v1 implementation relies on blocking IOs. This means you cannot use it together with Vert.x in a straightforward way. You would end up blocking the event-loop, hence killing your application's scalability. The only option would be to wrap your synchronous calls to AWS SDK v1 within executeBlocking or use a worker thread.

Even though some methods of the AWS SDK are indicated as "async" (DynamoAsyncClient for instance), it internally uses a thread pool whose size is configurable. Those threads can be a bottleneck in your application

You cannot really use AWS SDK v1 together with Vert.x in a non-blocking scalable way.

Embrace AWS SDK v2

Since 2018, AWS has published the version 2 of its SDK, embracing non-blocking IO model.

Now you can use V2 together with Vert.x using this project.

  • using Vert.x's HTTP client
  • CompletableFuture<?>'s are executed in the same Vert.x context that the one that made the request

Contributing

Tests placed under the io.vertx.ext.awssdk.integration package are using localstack: a huge set of utilities (docker images) emulating AWS Services (DynamoDB, Kinesis, S3, etc.).

In order to do so, they require a local docker daemon running on the machine.

They will download docker images from the docker hub, run the appropriate service as a docker container, then test the code against this local docker container.

They'll only be executed if the system property tests.integration is set to localstack. They'll be ignored otherwise.

Documentation

Documentation is docs/README.md and visible at https://github.com/reactiverse/aws-sdk/tree/master/docs or https://reactiverse.io/aws-sdk/

Javadoc can be produced (with Java 11 otherwise it does not link Vert.x API docs)

> ./gradlew javadocToDocsFolder

This will update the docs/javadoc with latest javadocs

aws-sdk's People

Contributors

aesteve avatar chris-brace avatar drx777 avatar jponge avatar vietj avatar wem avatar zhiguangwang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aws-sdk's Issues

VertxNioAsyncHttpClient vs AwsCrtAsyncHttpClient

I have vertical querying a dynamodb, i tested it using both AwsCrtAsyncHttpClient and VertxNioAsyncHttpClient.

AwsCrtAsyncHttpClient seems 55% faster than VertxNioAsyncHttpClient.

  1. DynamoDbAsyncClient using AwsCrtAsyncHttpClient (inside my Verticle start method)
DynamoDbAsyncClient dbAsyncClient =
            DynamoDbAsyncClient.builder()
                    .httpClient(AwsCrtAsyncHttpClient.builder().build())
                    .build();

Throughput = 12.4K rps

  1. DynamoDbAsyncClient using AwsCrtAsyncHttpClient (inside my Verticle start method)
DynamoDbAsyncClient dbAsyncClient = VertxSdkClient.withVertx(
                        DynamoDbAsyncClient.builder()
                        , context)
                .build();

Throughput = 7.7K rps

Not sure if i am doing something wrong, is it expected?
What is primary advantage of using VertxSdkClient vs building DynamoDbAsyncClient using aws sdk directly?

s3 object download

I am trying to download 1000s of S3 objects (2-6mb each) from an s3 bucket simultaneously. I've done basically nothing out of the ordinary. I'm constructing the s3asyncclient like this:

s3AsyncClient = VertxSdkClient.withVertx(S3AsyncClient.builder(), vertx.getOrCreateContext()).build();

and calling it like this:

    final Path p = PATH.resolve(UUID.randomUUID().toString());
    final CompletableFuture<GetObjectResponse> cf = s3AsyncClient.getObject(getLargeImageRequest(index), p);

The result, however, is a corrupted image that, from the looks of it is having its data written in the wrong order. This happens even if i only make one request. I did see #35 from last year and was able to get a single file downloading doing like this:

  Future<String> writeFile(Buffer data)
  {
    final Path p = PATH.resolve(UUID.randomUUID().toString() + ".jpg");
    final Promise<Void> promise = Promise.promise();
    vertx.fileSystem().writeFile(p.toString(), data, promise);
    return promise.future().map(p.toString());
  }

  Future<Buffer> getImage(int index, long length)
  {
    final String ebAddress = "s3-forward";
    final MessageProducer<Buffer> producer = vertx.eventBus().sender(ebAddress);
    final VertxAsyncResponseTransformer<GetObjectResponse> transformer = new VertxAsyncResponseTransformer<>(producer);

    final Buffer received = Buffer.buffer();
    final Promise<Buffer> promise = Promise.promise();
    vertx.eventBus().<Buffer>consumer(ebAddress, msg -> {
      received.appendBuffer(msg.body());
      if (received.length() == length)
      {
        promise.complete(received);
      }
    });

    s3AsyncClient.getObject(getLargeImageRequest(index), transformer);

    return promise.future();
  }

Is it expected that the default AWS SDK transformer for a Path object wont work out of the box? I guess i could use an event bus and my own async response transformer to stream data to file handles as it comes in but this seems like a lot of moving parts.

Can anyone advise how I should proceed here? I can upload the entire project very easily but its really not much more than what I pasted.

Working example of DynamoDb

Hi
I am trying to create vertx microservice accessing DynamoDb in the backend

Kindly provide some working example for the same

Also is this vertx client production ready?

Consider exposing Vert.x HttpClientOptions

My particular situation required supporting a proxy server, so I forked and hard coded the required additional ProxyOptions in the VertxNioAsyncHttpClient, where the Vert.x HttpClient is created.

It would perhaps be beneficial to support passing Vert.x HttpClientOptions as an optional parameter in the VertSdkClient.withVertx call?

VertxExecutor should use the Context instead of Vertx

Currently the VertxExecutor uses a Vertx instance for executing task. The AWS client uses it to dispatch back to the application when the response should be delivered to the application, however this is achieved internally by an async CompletableFuture completion on the ForkJoin pool which forces the executor to pick a new Vert.x Context.

Change the VertxExecutor to use instead of Context instance and use it for task execution.

s3: stream downloaded bytes?

Is it possible to stream/pump the bytes received from s3 to a vertx stream (like pushing the received bytes to a vertx HttpServerResponse). From looking at the code and tests, I think we would need a streaming implementation of AsyncResponseTransformer.toBytes, which would pump bytes as soon as they are available.
Or did I miss something and this already is possible?

Reduce the list of dependencies

Today, the project depends on: software.amazon.awssdk:aws-sdk-java:2.2.0
Which tears down every aws service implementation as a dependency.

This can really be problematic when building fatJars.
(example, in a Kotlin project, fatJar reduced from 140M down to 30M by using only Kinesis instead of the full aws-sdk).

One possibility, would be to set this dependency in compileOnly scope, and let the user decide which parts of the AWS SDK he needs. But this could lead to version clash.

Letting the user exclude / include sounds like a bad design.

Probably a cleaner solution can be found.

Problem with "Connection reset" for DynamoDB client

I'm using VertxSdkClient.withVertx to create my non-blocking DynamoDB client and it works. However, I see some occurrences of "Connection reset java.net.SocketException: Connection reset" (the full stack trace is given below) while running my application.

To try and get some more feedback, I added an exceptionHandler to VertxNioAsyncHttpClient like this:
`private HttpClient createVertxHttpClient(Vertx vertx) {
HttpClientOptions options = new HttpClientOptions()
.setSsl(true)
.setKeepAlive(true);

    return vertx.createHttpClient(options).connectionHandler(con -> {
        con.exceptionHandler(err -> {
            logger.error("VertxNioAsyncHttpClient connectionHandler.exceptionHandler: " + err.getMessage(), err);
        });
    });
}`

This exceptionHandler is getting called.
Any ideas what causes the "Connection reset" or what I can do to avoid them?

The full stack trace as being logged:
VertxNioAsyncHttpClient connectionHandler.exceptionHandler: Connection reset java.net.SocketException: Connection reset at java.base/sun.nio.ch.SocketChannelImpl.throwConnectionReset(SocketChannelImpl.java:345) at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:376) at io.netty.buffer.PooledByteBuf.setBytes(PooledByteBuf.java:247) at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:1147) at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:347) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:148) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:700) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:635) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:552) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:514) at io.netty.util.concurrent.SingleThreadEventExecutor$6.run(SingleThreadEventExecutor.java:1044) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:830)

Kotlin extension methods

@wem said:

Are you interested in Kotlin extensions for this library in a separate sub-lib like aws-sdk-lang-kotlin? I think about a collection of AWS SDK extensions with the Await approach, like most of the other Vert.x libraries have. I ask because it would be some work :)

I personally don't have enough knowledge in Kotlin koroutines to manage such a set of extension methods.

I think reactiverse maintainers should probably be consulted and give their opinion. But in the meantime, maybe @wem you could set the foundations of such a project in a personal repository, so that we can get a glimpse at what it looks like.

Try to use a JS lambda instead of a Python one

In its latest release, localstack broke the Python lambda support.

To get tests pass again, I simply @Disabled it, but in a near future, it'd be good to test with another type of lambda function (like a node.js one) instead, maybe this type of lambdas are still supported.

Worth the try so that we can have more tests.

Project not available through Maven

Hi folks! We'd love to use this project, but when we follow the readme to import this project in gradle, we're not able to resolve the artifact.

Would it be possible to start publishing releases for this project to a maven repo?

Travis CI

it would be great to have Travis integration for PR's

Compatible with Vert.x 3.7.1?

I am looking into using this library.
I saw the compatibility matrix, but wanted to ask anyway: Is this library compatible with Vert.x 3.7.1?

S3 list request signature verification failure due to missing query parameters in request

I was receiving a signature verification exception when trying to make an S3 list request. Making the request with both this Vert.x async client and the built-in client that AWS provides, I noticed that the request using Vert.x was missing the query parameters

Vert.x

GET / HTTP/1.1
amz-sdk-invocation-id: 8cd60990-8554-bb8c-3683-cd004c6c0c00
....

Built-in async client

GET /?prefix=some-prefix%2F HTTP/1.1
amz-sdk-invocation-id: 78f057b3-2e8a-e93b-213b-fb5ee1d31071
....

This fix to the VertxNioAsyncHttpClient worked:

    private static RequestOptions getRequestOptions(SdkHttpRequest request) {
        return new RequestOptions()
                .setHost(request.host())
                .setPort(request.port())
                .setURI(createRelativeUri(request.getUri()))
                .setSsl("https".equals(request.protocol()));
    }

    private static String createRelativeUri(URI uri) {
        return (StringUtils.isEmpty(uri.getPath()) ? "/" : uri.getPath()) +
                // AWS requires query parameters to be encoded as defined by RFC 3986.
                // see https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
                // uri.toASCIIString() returns the URI encoded in this manner
                (StringUtils.isEmpty(uri.getQuery()) ? "" : "?" + Strings.split(uri.toASCIIString(), "?")[1]);
    }

Support for the AWS Common Runtime S3 client

Please, add support for software.amazon.awssdk.services.s3.internal.crt.S3CrtAsyncHttpClient

Documentation https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/crt-based-s3-client.html

We have connectivity issues during data transfer, using the standard S3AsyncClient. From the documentation:

The AWS CRT-based S3 client improves transfer reliability in case there is a network failure. Reliability is improved by retrying individual failed parts of a file transfer without restarting the transfer from the beginning.

RxJava support

Are there plans in motion for adding RxJava(2) support? Also, could you add to the documentation that as the project stands, it is not compatible with vertx-rx?

Inconsistent behavior between S3AsyncClient with and without VertxSdkClient wrapper

Hi, I've noticed some strange behavior around S3AsyncClient when wrapping it with the reactiverse aws-sdk wrapper.

I'm currently running into an issue where trying to upload files where the s3 key contains a special character, in my scenario +, results in a signature mismatch expection.
java.util.concurrent.CompletionException: software.amazon.awssdk.services.s3.model.S3Exception: The request signature we calculated does not match the signature you provided. Check your key and signing method.

I dug a bit deeper, and to summarize my findings:

  • s3 does in-fact support these special characters
  • removing the special character results in a success
  • aws cli and aws web console allow this file to be uploaded to the expected key
  • The synchronous S3 client works
  • The async s3 client without the aws-sdk wrapper works

I was able to narrow down a JUnit 5 test scenario to outline the inconsistent results. The only thing you'll need to do to run it is update the bucket variable at the top with a bucket of the test.

import io.reactiverse.awssdk.VertxSdkClient;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.junit5.VertxExtension;
import io.vertx.junit5.VertxTestContext;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;

import java.nio.file.Path;
import java.util.UUID;

@ExtendWith(VertxExtension.class)
public class ReactiverseS3AsyncClientBug
{
    private static final AwsCredentialsProvider provider = DefaultCredentialsProvider.create();
    private static final Region region = Region.US_EAST_2;
    private static final String bucket = "my-bucket";
    private static final Path filePath = Path.of("sample_file.txt");

    @BeforeAll
    static void setup(Vertx v, VertxTestContext ctx)
    {
        final String text = "Some text data to store to disk";
        v.fileSystem().writeFile(filePath.toString(), Buffer.buffer(text)).onComplete(ctx.succeedingThenComplete());
    }

    @Test
    void uploadStuff_withSpecialChar_Async_reactiverseWrapper(final Vertx v, final VertxTestContext ctx)
    {
        final S3AsyncClient s3AsyncClient =
                VertxSdkClient.withVertx(S3AsyncClient.builder().credentialsProvider(provider).region(region),
                                         v.getOrCreateContext()).build();

        saveFileToS3(s3AsyncClient).onComplete(ctx.succeedingThenComplete());
    }

    @Test
    void uploadStuff_withSpecialChar_Async(final Vertx v, final VertxTestContext ctx)
    {

        final S3AsyncClient s3AsyncClient =
                S3AsyncClient.builder().credentialsProvider(provider).region(region).build();

        saveFileToS3(s3AsyncClient).onComplete(ctx.succeedingThenComplete());
    }

    private Future<PutObjectResponse> saveFileToS3(final S3AsyncClient client)
    {
        final String s3Key = "specialCharTest/Test_Sync_With_Special_Char&$@=;:+_" + UUID.randomUUID() + "_.txt";

        final PutObjectRequest reqObj = PutObjectRequest.builder().bucket(bucket).key(s3Key).build();
        return Future.fromCompletionStage(client.putObject(reqObj, filePath));
    }
}

The S3AsyncClient built with the VertxSdkClient.withVertx fails, where as the default one does not.

I ran into a similar case a while back where I abused the executeBlocking function on vertx to run the synchronous client as a work around. That scenario had similar behavior when trying to run s3AsyncClient.listObjectsV2, where it was failing when using the client wrapped by VertxSdkClient however passing without the wrapper.

I have not dove too deep into the investigation. Without special characters the putObject functionality works fine. From what I've read so far, special characters need to be url encoded when doing a http request. Its possible the encoding part is not working as intended causing the signature mismatch.

Let me know if I'm simply doing something wrong here, or if I can provide additional details to reproduce.

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.