How to inject an opentracing span into RabbitMQ? - 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)

Related

WidgetKit not calling urlSessionDidFinishEvents

I'm trying to implement downloading timeline data in a widget and so I created a background URLSession with a corresponding data task to download the JSON:
let session = URLSession(
configuration: .background(withIdentifier: identifier),
delegate: self,
delegateQueue: nil
)
let request = URLRequest(url: ...)
session.dataTask(with: request).resume()
On my widget I then added the onBackgroundURLSessionEvents to store the completion handler, as per the Apple docs:
.onBackgroundURLSessionEvents { identifier in
return SessionCache.shared.isValid(for: identifier)
} _: { identifier, completion in
let data = SessionCache.shared.sessionData(for: identifier)
data.sessionCompletion = completion
}
However, neither the urlSessionDidFinishEvents(forBackgroundURLSession:) nor the onBackgroundURLSessionEvents methods are called. When the network download completes, it just calls the normal urlSession(_:task:didCompleteWithError:) method.
I'm clearly missing something here, but I'm just not seeing what.
Apple's documentation isn't 100% clear on this, but you need to use URLSession.downloadTask instead of dataTask for background sessions. URLSessionDataTasks deliver bytes to those specific delegate methods in your in-memory process. Background download & upload tasks are handed off to nsurlsessiond and only delivered back to your app when they are fully resolved.

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?

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

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.

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).

How to make python apscheduler trigger a function inside a class instance

I have a class which has BaseScheduler as an attribute, nothing fancy, no frameworks etc.
class MyClass(object):
def __init__(self, ...):
...
self.Scheduler = BackgroundScheduler()
...
Later on I define methods that a) schedule jobs based on a schedule definition passed as kwargs, and b) handle the jobs when they are triggered:
def _schedule_Events(self, *args, **kwargs):
try:
Schedule_Def = kwargs.copy()
Schedule_Def['func'] = self._handle_scheduled_Event
job = self.Scheduler.add_job(**Schedule_Def)
self.Scheduled_Events.append(job)
except Exception as e:
self.Logger.exception('%s: exception in schedule_Events, details: %s' %(self.Name, e))
def _handle_scheduled_Event(self, Event_Action):
""" Callback function for scheduled jobs """
try:
.... do stuff ....
However, adding jobs with _schedule_Events fails with:
File "/usr/local/lib/python3.4/dist-packages/apscheduler/util.py", line 381, in check_callable_args
', '.join(unsatisfied_args))
ValueError: The following arguments have not been supplied: Event_Action
The reason is apparently that the 'func' argument must be globally callable, ie. not within a class instance scope. I also don't see how using a 'textual reference' as described in the documentation will help.
If I replace the 'func' callable with a function defined at the module level then it works, but I need to make it call a method within my instance object. Any ideas how to make this work ? Custom trigger ? Wrapping APS Scheduler inside another class and pass the callback ? Other ideas ?
Many thanks in advance.