route failureHandler is blocked in SmallRye Mutiny Vertx bindings - vert.x

I tried to experience the SmallRye Mutiny Vertx bindings, the complete example codes can be found on my Github.
When assembling the routings like this.
router.get("/posts/:id").produces("application/json")
.handler(handlers::get);
//.failureHandler(frc -> frc.response().setStatusCode(404).end());
The failureHandler will block the request.

The problem here is that end returns a Uni object. You can think of it as a function. This function is lazy. What you want to do instead is call that function. This can be achieved by subscribing to it.
If you're not interested in processing the result of this Uni, you can use endAndForget instead of end which will call that function for you (subscribe to the Uni).
If you would like to do something with the result of the Uni, you can subscribe instead:
.failureHandler(frc ->
frc.response()
.setStatusCode(404)
.end()
.subscribe().with(ignore -> System.out.println("failure handler is done"))
);

Related

Different Handlers for URL patterns (same prefix) in vertx

I'm using vertx-4.x. I've sample url patterns like this:
api/v1/xyz_development/sse/reference/123456/ -> Handler1
api/v1/xyz_development/members/reference/789045/ -> Handler2
Please note xyz_development is not fixed. It might change based on environment, so i don't want to hardcode it in URL patterns.
Requests with url pattern with /sse should be handled by Handler1 and any other requests shoud be handled by Handler2.
I'm registering routes like this:
router.route("/sse/*).handler(new Handler1());
router.route("/api/v1/*).handler(new Handler2());
But when requests come with /sse , those are going to Handler2 instead of Handler1 as prefix is same (/api/v1/...)
I tried subRouters and pathRegex() API as well but couldn't make it work. Please suggest a way to acheive this.
Change the order of your route declarations:
router.route("/api/v1/xyz_development/sse/*").handler(new Handler2());
router.route("/api/v1/xyz_development/*").handler(new Handler1());
And then requests for SSE will be handled by Handler2.
After couple of trial and errors, finally found the solution. Defining routes like below worked:
router.route().pathRegex("/api/v1/.*/sse/.*").handler(new Handler1());
router.route().path("/api/v1/*").handler(new Handler2());
Now requests with /sse are being handled by Handler1 and other requests are being handled by Handler2.
I welcome if there are other ways to achieve this.

How to make a http request in a playground update function?

I want to make http requests from my elm program.
I use the openapi-generator https://eriktim.github.io/openapi-elm for the http requests:
https://github.com/eriktim/openapi-elm,
The only example I could find is this:
https://github.com/eriktim/openapi-elm/tree/master/example
There, a request has e.g. type Api.Request Api.Data.PlanetList and is converted with the send function: (Result Http.Error a -> msg) -> Request a -> Cmd msg.
The send function takes a function to convert the Request result to msg but but returns it wrapped in Cmd.
The update function has type
update : Msg -> Model -> ( Model, Cmd Msg )
So as long as the request is made in the update function and the result is put in the return value the framework will get msg out of Cmd.
Now I want to make requests in my program, but I'm using playground game as my main function (example) where the update function is update : Computer -> Model -> Model so the "trick" from the example project is not applicable. How can I still get the values from my request call then?
A Http request is a piece of data for the runtime to execute. If the Cmd is not passed to the runtime through the main update, the actual http call will never happen.
This is why you cannot have side-effects in simple programs (Playground and Browser.sandbox).
I'm not really sure what elm-playground is, but that's not the right starting point for a webapp such as you want to create, as it does not support Commands, such as Http requests.
You want to be using normal / standard Elm - see https://guide.elm-lang.org/install/elm.html and then you want to be building a Program based on Browser.document - https://guide.elm-lang.org/webapps/
Hope that gets you on your way

RxJava2 Single does not handle error even if doOnerror is provided

I've encountered an issue using RxJava2 (version 2.2.2). See the code below:
client.get("/iic-router/health").rxSend()
.doOnError(err -> { err.printStackTrace(); async.complete(); })
.doOnSuccess(v -> async.complete())
.subscribe();
As you can see, the rxSend() method returns an instance of Single. When I run this code and the WebServer is not started I get an error of Connectiong Refused (as expected), but I get an error:
io.reactivex.exceptions.OnErrorNotImplementedException: The exception
was not handled due to missing onError handler in the subscribe() method call.
If I change the code for more traditional way on RxJava like this:
client.get("/iic-router/health").rxSend().subscribe(
v -> async.complete(),
err -> { err.printStackTrace(); async.complete(); }
);
Everything works well. Anyone can help me ? Or it's a real bug ?
This is not a bug and the simple subscribe() is documented:
Subscribes to a Single but ignore its emission or notification.
If the Single emits an error, it is wrapped into an OnErrorNotImplementedException and routed to the RxJavaPlugins.onError handler.
The OnErrorNotImplementedException said that you need to implement the onError Handler, like you did in your second example.
Instead of doOnError, you can also try onErrorResumeNext or onErrorReturn which won't invoke onError on subscribe.

Lambda + API Gateway: Long executing function return before task finished

I have a function in Lambda that executes for up to 30s depending on the inputs.
That function is linked to an API gateway so I am able to call it through POST, unfortunatly the API Gateway is limited to 30s exaclty, so if my function runs for longer I get an "internal server error" back from my POST.
I see 2 solutions to this:
Create a "socket" rather then a simple POST which connects to the lambda function, not sure if this is even possible or how would this work.
Return a notification to api gateway before the lambda function is actually finished. This is acceptable for my use case, but I am not sure again how would this work.
The function is coded in Python3.6 I therefore have access to the event and context object.
Return a notification to api gateway before the lambda function is actually finished. This is acceptable for my use case, but I am not sure again how would this work.
Unfortunately, you will not be able to return a result until the Lambda is finished. Otherwise, AWS will interrupt execution of Lambda if you try to do it, for example, via multithreading.
I suggest you create the following system:
API Gateway puts a request to Kinesis stream and returns a response of successfully putting. The response will contain SequenceNumber of the Kinesis Record. (How to do it)
Lambda is invoked by Kinesis Stream Event, processes the request and saves that your job is done (or completed result) to DynamoDB with SequenceNumber as id.
You invoke another API Gateway method and SequenceNumber to check the status of your job in DynamoDB (if necessary).
If you need just to run the Lambda without knowing of job result you can avoid using DynamoDB.
statut approach is nice, but I'd like to give you an alternative: AWS step functions. Basically it does what statut's solution does but it might be more easy to deploy.
All you have to do is to create an AWS Step Functions state machine that has your lambda function as its only task. AWS Step functions intrinsically works asynchronously, and has methods to know the status and, eventually, the result. Check the docs for more info.
A very simple solution would be for your lambda function to just asynchronously invoke another lambda function and then return a result to API Gateway.
Here's a real example of executing one lambda function asynchronously from another lambda function:
import json
import boto3
def lambda_handler(event, context):
payload = {}
##take the body of the request and convert to string
body = json.loads(event['body'])
##build new payload with body and anything else your function downstream needs
payload['body'] = json.dumps(body)
payload['httpMethod'] = 'POST'
payloadStr = json.dumps(payload)
client = boto3.client('lambda')
client.invoke(
FunctionName='container name',
InvocationType="Event",
Payload=payloadStr
)
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
In this example, the function invokes the other one and returns right away.
invoke documentation: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda.html#Lambda.Client.invoke

RxSwift - Fetch undetermined resources via HTTP

I have undetermined resources that need to be fetched from a server. I tried to accomplish this by using the repeatElement() and concat() operators like this:
repeatElement(0, CurrentThreadScheduler.instance).map({ _ -> Observable<[Task]> in
// API.getTasks() uses Alamofire to request data
return API.getTasks(loggedUser, after: loggedUser.taskPullTime)
}).concat().takeWhile({ (tasks) -> Bool in
return tasks.count > 0
})
Unfortunately, repeatElement will just emit an item without waiting for the old one to be handled. I think the reason is that Alamorfire executes in a private serial queue.
However, I cannot figure out how to solve this problem.
I used the strategy inspired from here in my Android project. Everything works fine because Retrofit init HTTP request in a synchronous manner.