Pika: How to get a return value from a callback function? - rabbitmq

I have a callback function in my program that I need to check success/failure. How can I do this?
In my example below, where does failure_code go?
My snippet:
def mq_callback(job_id, ch, method, body):
# Do some stuff. But if the stuff fails...
return failure_code
channel.basic_consume(
queue='some queue',
on_message_callback=lambda ch, method, properties, body: mq_callback(job_id, ch, method, body),
auto_ack=False
)
channel.start_consuming()

All in this link: https://www.rabbitmq.com/tutorials/tutorial-six-python.html
We create a class for calling requests then wait until the response id equal to the correlation_id that was sent before.

Related

Spring Webflux returning null back to controller

Every time I think I understand Webflux and project reactor, I find out I have no idea.
So I making some API calls... I want to call 1 first ... Get information back use that information, to make subsequent calls.
so I do this like so
public Mono<ResponseObject> createAggregatedRecords(RecordToPersist recordToPersist){
return randomApiClient.createRecord(recordToPersist)
.flatMap(result -> {
return Mono.zip(
webClientInstance.createOtherRecord1(result.getChildRecord1()),
webClientInstance2.createOtherRecord2(result.getChildRecord2()),
webClientInstance3.createOtherRecord3(result.getChildRecord3()))
.map(tupple -> {
ResponseObject respObj = new ResponseObject();
respObj.setChildResult1(tupple.getT1());
respObj.setChildResult2(tupple.getT2());
respObj.setChildResult3(tupple.getT3());
return respObj;
}
}).doOnSuccess(res -> log.info("This throws an error: {}", res.getChildResult1.getFirstField()))
}
Now, for some reason, I am returning a null object with this very code to my Controller and I am not printing out the object in Json.
I suspect it is because I am nesting the Mono.zip inside the flatmap, and am not returning the results back correctly. I am making all of those API calls though as my End-to-End integration tests are succeeding.
Now I thought that I would return that response object from the .map function from the Mono.zip chain and then return that to the flatMap call in the chain. If I put observers on the chain like a doOnSuccess and print out response object fields I get a null pointer ... Not sure what I am missing
Is this a good pattern to achieve that goal? Or should I try a different path?
Why can I not get the response Object to return?

Return 404 when a Flux is empty

I am trying to return a 404 when a Flux is empty, similar to here:WebFlux functional: How to detect an empty Flux and return 404?
My main concern is that, when you check if the flux has elements it emmits that value and you loose it. And when I try to use switch if empty on the Server Response it is never called (I secretly think it is because the Mono is not empty, only the body is empty).
Some code of what I am doing (I do have a filter on my Router class checking for DataNotFoundException to return a notFound):
Flux<Location> response = this.locationService.searchLocations(searchFields, pageToken);
return ok()
.contentType(APPLICATION_STREAM_JSON)
.body(response, Location.class)
.switchIfEmpty(Mono.error(new DataNotFoundException("The data you seek is not here.")));
^This never calls switchIfEmpty
Flux<Location> response = this.locationService.searchLocations(searchFields, pageToken);
return response.hasElements().flatMap(l ->{
if(l){
return ok()
.contentType(APPLICATION_STREAM_JSON)
.body(response, Location.class);
}
else{
return Mono.error(new DataNotFoundException("The data you seek is not here."));
}
});
^This looses the emitted element on hasElements.
Is there a way to either recover the emitted element in hasElements or to make the switchIfEmpty only check the contents of the body?
You could apply switchIfEmpty operator to your Flux<Location> response.
Flux<Location> response = this.locationService
.searchLocations(searchFields, pageToken)
.switchIfEmpty(Mono.error(new DataNotFoundException("The data you seek is not here.")));
while the posted answers are indeed correct, there is a convenience exception class if you just want to return a status code (plus a reason) and do not want to fiddle with any custom filters or defining your own error response exceptions.
The other benefit is that you do not have to wrap your responses inside of any ResponseEntity Objects, while useful for some cases (for example, created with a location URI), is an overkill for simple status responses.
see also https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/server/ResponseStatusException.html
return this.locationService.searchLocations(searchFields, pageToken)
.buffer()
.switchIfEmpty(Mono.error(new ResponseStatusException(HttpStatus.NOT_FOUND, "these are not the droids you are lookig for")));
What Alexander wrote is correct. You call switchIfEmpty on the Object that is never empty ServerResponse.ok() by definition is not a empty Publisher. I like to handle this cases in revers so invoke the service and then chain all the methods that create the response.
this.locationService.searchLocations(searchFields, pageToken)
.buffer()
.map(t -> ResponseEntity.ok(t))
.defaultIfEmpty(ResponseEntity.notFound().build());
UPDATE (not sure if it works, but give it a try):
public Mono<ServerResponse> myRestMethod(ServerRequest serverRequest) {
return serverRequest.bodyToMono(RequestDTO.class)
.map((request) -> searchLocations(request.searchFields, request.pageToken))
.flatMap( t -> ServerResponse
.ok()
.body(t, ResponseDTO.class)
)
.switchIfEmpty(ServerResponse.notFound().build())
;
}

How to inject an opentracing span into RabbitMQ?

I´m using OpenTracing and I am trying to propagate a span through RabbitMQ. However I don't understand how I am supposed to inject the span and how to extract it later.
This is the code for sending a message
def send_message(self, message, tracer):
root_span = tracer.get_span()
with opentracing.tracer.start_span('Sending message to broker', child_of=root_span) as span:
connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()
channel.queue_declare(queue='default')
json_message = json.dumps(message)
channel.basic_publish(exchange='',
routing_key='default',
body=json_message)
connection.close()`
And I have a callback function for receiving the message
def _callback(self, ch, method, properties, body):
print(" [x] Received %r" % body)
So somewhere and somehow I want to inject the span and then extract it. Does anyone know or have any examples on how to do it?
I have tried to inject before calling basic_publish in sender like this
tracer.inject(span, Format.HTTP_HEADERS, headers)
But I have no idea which arguments are going to the inject method.
Then I tried to extract it like this in the callback
span_ctx = tracer.extract(Format.HTTP_HEADERS, {})
Again, I don't know which arguments are going into the extract method.
EDIT: solved, kinda
I solved it by sending the carrier into properties header. Then I could extract the span from the callback properties attribute
In the sender:
channel.basic_publish(exchange='',
routing_key='default',
properties=pika.BasicProperties(headers=carrier),
body=json_message)
In the callback, extract span:
def _callback(self, ch, method, properties, body):
span_ctx = tracer.extract(Format.TEXT_MAP, properties.headers)
I solved it by sending the carrier into properties header. Then I could extract the span from the callback properties attribute
In the sender:
channel.basic_publish(exchange='',
routing_key='default',
properties=pika.BasicProperties(headers=carrier),
body=json_message)
In the callback, extract span:
def _callback(self, ch, method, properties, body):
span_ctx = tracer.extract(Format.TEXT_MAP, properties.headers)

How to stop replyTo so that #SendTo works

I have Java code similar to this in a class called "MyService" to receive messages, process the object passed and return a response, with the intention to have the returned response using the configured exchange and routing key, as specified using the #SendTo annotation:
#RabbitListener(containerFactory = "myContainerFactory", queues = RabbitConfig.MY_QUEUE_NAME)
#SendTo("#{T(com.acme.config.RabbitOutboundConfig).OUTBOUND_EXCHANGE_NAME + '/' + myService.getRoutingKey()}")
public OrderResponse handlePaidOrder(Order order) {
// do processing on the input Order object here...
OrderResponse orderResponse = new OrderResponse();
// fill up response object here
return orderResponse;
}
public String getRoutingKey() {
String routingKey;
// .. custom logic to build a routing key
return routingKey;
}
This makes sense and works fine. The problem I am having is I can't figure out how to stop the "reply_to" property from coming in the message. I know if my sender configures a RabbitTemplate by calling setReplyAddress, that will result in a reply_to property and a correlation_id in the message.
However, if I simply do not call setReplyAddress, I still get a reply_to property, one that looks like this:
reply_to: amq.rabbitmq.reply-to.g2dkAAxyYWJiaXRAd3NK and so forth
and with that reply_to in the message, #SendTo has no effect. The Spring AMQP docs and this post: Dynamic SendTo annotation state:
The #SendTo is only used if there's no replyTo in the message.
Furthermore, when I don't call setReplyAddress on the RabbitTemplate, I don't get a correlation-id either. I pretty sure I am going to need that. So, my question is, how do I get my sender to generate a correlation-id but to not generate a reply-to so that my receiver can use the #SendTo annotation?
Thanks much in advance.
The correlationId is for the sender; it's not needed with direct reply-to since the channel is reserved; you could add a MessagePostProcessor on the sending side to add a correlationId.
The #SendTo is a fallback in case there is no reply_to header.
If you want to change that behavior you can add an afterReceivePostProcessor to the listener container to remove the replyTo property on the MessageProperties.
container.setAfterReceivePostProcessor(m -> {
m.getMessageProperties().setReplyTo(null);
return m;
}
Bear in mind, though, that if the sender set a replyTo, he is likely expecting a reply, so sending the reply someplace else is going to disappoint him and likely will cause some delay there until the reply times out.
If you mean you want to send an initial reply someplace else that does some more work and then finally replies to the originator, then you should save off the replyTo in another header, and reinstate it (or use an expression that references the saved-off header).

What does JQuery do with randomly generated callback name for JSONP?

so since Ajax generates something like this for the request
callback=jQuery19104342058659531176
and in the end server returns
jQuery19104342058659531176(data)
what does it call if jQuery19104342058659531176() function is (obviously) not defined?
I understand it will go to success/error handler, but dont really get the purpose of the callback then?
in fact, jQuery will invoke the callback, then invoke success/error.
If you omit "jsonpCallback", then jQuery will invoke the default one deined by jQuery. the source code is in jsonp.js:
window[ callbackName ] = function() {
responseContainer = arguments;
};