Vertx - Multiple failureHandlers for the same route - vert.x

The question is simple: is it possible to have multiple failure handlers for one route?
router.route(HttpMethod.POST, "/test")
.handler(LoggerHandler.create())
.handler(ResponseTimeHandler.create())
.failureHandler(MyCustomFailureHandler1.create())
.failureHandler(MyCustomFailureHandler2.create());
I'm currently using vert.x version 4.0.2, and I can see that internally, every failure handler I create is added to a failureHandlers list, but when an error is thrown, the only failure handler executing is the first one specified.

From the first failure handler (MyCustomFailureHandler1.create()), you have to call RoutingContext#next()
Documentation of RoutingContext#next() states: "If next is not called for a handler then the handler should make sure it ends the response or no response will be sent".
See TestCase here: testMultipleSetFailureHandler

Related

Getting OperationResult when ResultUrl is not in response object?

I am turning to the community as I haven't found anything in the official documentation.
As the title says, I am having troubles fetching the operation result. I am creating an operation by calling the Project - Create REST endpoint. The HTTP call is responding with the operation reference, as the operation is successfully queued. While the operation is running (States NotSet, Queued, InProgress), I am polling the operation at an 300 ms interval. After several seconds, the operation results in a success state.
As the operation was successful, I would expect that the resultUrl property of the Operation is populated with the URL pointing to the created resource (in my case in the form of https://dev.azure.com/{organization}/_apis/projects/{projectId}?api-version=6.0). However, resultUrl is not part of the response of the GET call at all.
Is there anything I am missing or misinterpreting? Any help is appreciated, thanks in advance.
The problem is not clear in your question. If you create a new project, you know its name. The URL to projects is stable:
https://dev.azure.com/{organization}/_apis/projects/{projectNAME}?api-version=6.0
You can get ProjectState in the answer and any over information like the project URL (TeamProject).

How to handle commands sent from saga in axon framework

Using a saga, given an event EventA, saga starts, it sends a command (or many).
How can we make sure that the command is sent successfully then actual logic in other micro-service did not throw, etc.
Let's have an example of email saga:
When a user register, we create a User Aggregate which publishes UserRegisteredEvent, a saga will be created and this saga is responsible to make sure that registration email is sent to user (email may contain a verification key, welcome message, etc).
Should we use :
commandGateway.sendAndWait with a try/catch -> does it scale?
commandGateway.send and use a deadline and use some kind of "fail event" like SendEmailFailedEvent -> requires to associate a "token" for commands so can associate the "associationProperty" with the correct saga
that sent SendRegistrationEmailCommand
commandGateway.send(...).handle(...) -> in handle can we reference eventGateway/commandGateway that were in MyEmailSaga?
If error we send an event? Or can we modify/call a method from the saga instance we had. If no error then other service have sent an event like "RegistrationEmailSentEvent" so saga will end.
use deadline because we just use "send" and do not handle the eventual error of the command which may have failed to be sent (other service is down, etc)
something else?
Or a combination of all?
How to handle errors below? (use deadline or .handle(...) or other)
Errors could be:
command has no handlers (no service up, etc)
command was handled but exception is raised in other service and no event is sent (no try/catch in other service)
command was handled, exception raised and caught, other service publish an event to notify it failed to send email (saga will receive event and do appropriate action depending on event type and data provided -> maybe email is wrong or does not exist so no need to retry)
other errors I missed?
#Saga
public class MyEmailSaga {
#Autowired
transient CommandGateway commandGateway;
#Autowired
transient EventGateway eventGateway;
#Autowired
transient SomeService someService;
String id;
SomeData state;
/** count retry times we send email so can apply logic on it */
int sendRetryCount;
#StartSaga
#SagaEventHandler(associationProperty = "id")
public void on(UserRegisteredEvent event) {
id = event.getApplicationId();
//state = event........
// what are the possibilities here?
// Can we use sendAndWait but it does not scale very well, right?
commandGateway.send(new SendRegistrationEmailCommand(...));
// Is deadline good since we do not handle the "send" of the command
}
// Use a #DeadlineHandler to retry ?
#DeadlineHandler(deadlineName = "retry_send_registration_email")
fun on() {
// resend command and re-schedule a deadline, etc
}
#EndSaga
#SagaEventHandler(associationProperty = "id")
public void on(RegistrationEmailSentEvent event) {
}
}
EDIT (after accepted answer):
Mainly two options (Sorry but kotlin code below):
First option
commandGateway.send(SendRegistrationEmailCommand(...))
.handle({ t, result ->
if (t != null) {
// send event (could be caught be the same saga eventually) or send command or both
}else{
// send event (could be caught be the same saga eventually) or send command or both
}
})
// If not use handle(...) then you can use thenApply as well
.thenApply { eventGateway.publish(SomeSuccessfulEvent(...)) }
.thenApply { commandGateway.send(SomeSuccessfulSendOnSuccessCommand) }
2nd option:
Use a deadline to make sure that saga do something if SendRegistrationEmailCommand failed and you did not receive any events on the failure (when you do not handle the command sent).
Can of course use deadline for other purposes.
When the SendRegistrationEmailCommand was received successfully, the receiver will publish an event so the saga will be notified and act on it.
Could be an RegistrationEmailSentEvent or RegistrationEmailSendFailedEvent.
Summary:
It seems that it is best to use handle() only if the command failed to be sent or receiver has thrown an unexpected exception, if so then publish an event for the saga to act on it.
In case of success, the receiver should publish the event, saga will listen for it (and eventually register a deadline just in case); Receiver may also send event to notify of error and do not throw, saga will also listen to this event.
ideally, you would use the asynchronous options to deal with errors. This would either be commandGateway.send(command) or commandGateway.send(command).thenApply(). If the failure are businesslogic related, then it may make sense to emit events on these failures. A plain gateway.send(command) then makes sense; the Saga can react on the events returned as a result. Otherwise, you will have to deal with the result of the command.
Whether you need to use sendAndWait or just send().then... depends on the activity you need to do when it fails. Unfortunately, when dealing with results asynchronously, you cannot safely modify the state of the Saga anymore. Axon may have persisted the state of the saga already, causing these changes to go lost. sendAndWait resolves that. Scalability is not often an issue, because different Sagas can be executed in parallel, depending on your processor configuration.
The Axon team is currently looking at possible APIs that would allow for safe asynchronous execution of logic in Sagas, while still keeping guarantees about thread safety and state persistence.

How to add a failure callback for kafka-python kafka.KafkaProducer#send()?

I would like to set a callback to be fired if a produced records fail. Initially, I would just like to log the failed record.
The Confluent Kafka python library provides a mechanism for adding a callback:
produce(topic[, value][, key][, partition][, on_delivery][, timestamp])
...
on_delivery(err,msg) (func) – Delivery report callback to call (from poll() or flush()) on successful or failed delivery
How can I achieve similar behaviour with kafka-python kafka.KafkaProducer#send() without having to use the deprecated SimpleClient using kafka.SimpleClient#send_produce_request()
Although it isn't documented, this is relatively straightforward. Whenever you send a message, you immediately get a Future back. You can append callbacks/errback's to that Future:
F = producer.send(topic=topic, value=message, key=key)
F.add_callback(callback, message=message, **kwargs_to_pass_to_callback_method)
F.add_errback(erback, message=message, **kwargs_to_pass_to_errback_method)
Relevant source code here:
https://github.com/dpkp/kafka-python/blob/1937ce59b4706b44091bb536a9b810ae657c3225/kafka/future.py#L48-L64
We really should document this, I filed https://github.com/dpkp/kafka-python/issues/1256 to track it.

cancel request when its already finished

consider the following (pseudo) code:
let request = Alamofire.request(...) {
//handler called when requests has been completed
//do some processing here
}
//some processing here, could take a while
request.cancel()
Question:
what happens if the request has already been fully completed (and the handler called) when the request.cancel() is done?
Will this return an error?
Is the handler called again?
Or (what I am hoping for) nothing...?
If the handler called that means request has its answer that can mean two things: Either request is succesfull, you have what you asked or request is not succesfull which means you will get an error.
Either way if you got your response request.cancel() will mean nothing.

How do I call a method on my ServiceWorker from within my page?

I have a ServiceWorker registered on my page and want to pass some data to it so it can be stored in an IndexedDB and used later for network requests (it's an access token).
Is the correct thing just to use network requests and catch them on the SW side using fetch, or is there something more clever?
Note for future readers wondering similar things to me:
Setting properties on the SW registration object, e.g. setting self.registration.foo to a function within the service worker and doing the following in the page:
navigator.serviceWorker.getRegistration().then(function(reg) { reg.foo; })
Results in TypeError: reg.foo is not a function. I presume this is something to do with the lifecycle of a ServiceWorker meaning you can't modify it and expect those modification to be accessible in the future, so any interface with a SW likely has to be postMessage style, so perhaps just using fetch is the best way to go...?
So it turns out that you can't actually call a method within a SW from your app (due to lifecycle issues), so you have to use a postMessage API to pass serialized JSON messages around (so no passing callbacks etc).
You can send a message to the controlling SW with the following app code:
navigator.serviceWorker.controller.postMessage({'hello': 'world'})
Combined with the following in the SW code:
self.addEventListener('message', function (evt) {
console.log('postMessage received', evt.data);
})
Which results in the following in my SW's console:
postMessage received Object {hello: "world"}
So by passing in a message (JS object) which indicates the function and arguments I want to call my event listener can receive it and call the right function in the SW. To return a result to the app code you will need to also pass a port of a MessageChannel in to the SW and then respond via postMessage, for example in the app you'd create and send over a MessageChannel with the data:
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function(event) {
console.log(event.data);
};
// This sends the message data as well as transferring messageChannel.port2 to the service worker.
// The service worker can then use the transferred port to reply via postMessage(), which
// will in turn trigger the onmessage handler on messageChannel.port1.
// See https://html.spec.whatwg.org/multipage/workers.html#dom-worker-postmessage
navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]);
and then you can respond via it in your Service Worker within the message handler:
evt.ports[0].postMessage({'hello': 'world'});
To pass data to your service worker, the above mentioned is a good way. But in case, if someone is still having a hard time implementing that, there is an other hack around for that,
1 - append your data to get parameter while you load service-worker (for eg., from sw.js -> sw.js?a=x&b=y&c=z)
2- Now in service worker, fetch those data using self.self.location.search.
Note, this will be beneficial only if the data you pass do not change for a particular client very often, other wise it will keep changing the loading url of service worker for that particular client and every time the client reloads or revisits, new service worker is installed.