TryReceive method on IMessageReceiver interface - azure-service-fabric

Please provide the following methods in IMessageReceiver:
bool TryReceive(out Message msg, TimeSpan timeout)
Task<bool> TryReceiveAsync(out Message msg, TimeSpan timeout)
So that we can use these like:
if (TryReceive(out Message msg, TimeSpan.FromSeconds(30))
{
...
}
else
{
...
}

If you want to make a feature request for Azure Functions you can leave that feedback here: https://feedback.azure.com/forums/355860-azure-functions

Related

MailKit version 2.15.0 disconnection issue

I am using MailKit version 2.15.0. When trying to disconnect the client using DisconnectAsync, I am getting the below error
ClientDisconnect method()==> Exception Message: The ReadAsync method cannot be called when another read operation is pending., Exception String: System.NotSupportedException: The ReadAsync method cannot be called when another read operation is pending.
at System.Net.Security.SslStream.ReadAsyncInternal[TIOAdapter](TIOAdapter adapter, Memory`1 buffer)
at MailKit.Net.Pop3.Pop3Stream.ReadAheadAsync(Boolean doAsync, CancellationToken cancellationToken)
at MailKit.Net.Pop3.Pop3Stream.ReadLineAsync(Stream ostream, Boolean doAsync, CancellationToken cancellationToken)
at MailKit.Net.Pop3.Pop3Engine.ReadLineAsync(Boolean doAsync, CancellationToken cancellationToken)
at MailKit.Net.Pop3.Pop3Engine.ReadResponseAsync(Pop3Command pc, Boolean doAsync)
at MailKit.Net.Pop3.Pop3Engine.IterateAsync(Boolean doAsync)
at MailKit.Net.Pop3.Pop3Client.SendCommandAsync(Boolean doAsync, CancellationToken token, String command)
at MailKit.Net.Pop3.Pop3Client.DisconnectAsync(Boolean quit, Boolean doAsync, CancellationToken cancellationToken)
Below is the code I am using to Disconnect the Client
private async Task DisconnectClient(Hashtable markAsRead, EmailServer emailServer)
{
pollingInProgress = false;
await emailServer.ClientDisconnect(markAsRead);
markAsRead.Clear();
}
internal void MarkAsRead(Hashtable markAsRead)
{
emailBinding.emailSource().MarkRead(markAsRead);
}
internal async Task ClientDisconnect(Hashtable markAsRead)
{
try
{
if (!emailBinding.emailSource().IsConnected)
{
await emailBinding.Connect();
}
FlushClient(markAsRead);
await emailBinding.Disconnect();
}
catch (Exception e)
{
AttachWorkerLogs(string.Format("ClientDisconnect method()==> Exception Message: {0}, Exception String: {1}", e.Message, e.ToString()));
throw;
}
}
private void FlushClient(Hashtable markAsRead)
{
MarkAsRead(markAsRead);
}
Finally calling the disconnect method like this:
public async Task Disconnect()
{
try
{
if (client.IsConnected)
{
await client.DisconnectAsync(true);
}
}
catch (Exception e)
{
AttachLogger(string.Format("Disconnect method()==> Exception Message: {0}, Exception String: {1}", e.Message, e.ToString()));
throw;
}
}
I am unable to figure out what exactly is the issue.
The exception message makes it pretty clear that you are trying to read from the SslStream from multiple threads at the same time.
Since MailKit is not multi-threaded, it means that you are effectively trying to perform 2 or more operations on the same Pop3Client from multiple threads at the same time.
In other words, the problem is not that you are calling Disconnect, the problem is that you are calling Disconnect when your code is also trying to download messages or something from the server.

Reply Kafka Template - Exception handling

I am using ReplyingKafkaTemplate to establish a synchronous call between two microservices.
The receiver of the event is annotated with SendTo as below:
#KafkaListener(topics = "${kafka.topic.prefix}"
+ "${kafka.topic.name}", containerFactory = "customEventKafkaListenerFactory")
#SendTo
public CustomResponseEvent onMessage(
#Payload #Valid CustomRequestEvent event, #Header(KafkaHeaders.CORRELATION_ID) String correlationId,
#Header(KafkaHeaders.REPLY_TOPIC) String replyTopic) {
//Making some REST API calls to another external system here using RestTemplate
}
The REST API call can throw a 4xx or 5xx. There are multiple such calls, some to internal systems, and some to external systems. It may be a bad design, but let's not get into that.
I would like to have a global exception handler for the RestTemplate where I can catch all the exceptions, and then return a response to the original sender of the event.
I am using the same replyTopic and correlationId as received in the consumer to publish the event.
But still the receiver of the response throws No pending reply exception.
Whatever approach I have above, is it possible to achieve such a central error response event publisher?
Is there any other alternative that is best suited for this exception handling?
The #KafkaListener comes with the:
/**
* Set an {#link org.springframework.kafka.listener.KafkaListenerErrorHandler} bean
* name to invoke if the listener method throws an exception.
* #return the error handler.
* #since 1.3
*/
String errorHandler() default "";
That one is used to catch and process all the downstream exceptions and if it returns a result, it is sent back to the replyTopic:
public void onMessage(ConsumerRecord<K, V> record, Acknowledgment acknowledgment, Consumer<?, ?> consumer) {
Message<?> message = toMessagingMessage(record, acknowledgment, consumer);
logger.debug(() -> "Processing [" + message + "]");
try {
Object result = invokeHandler(record, acknowledgment, message, consumer);
if (result != null) {
handleResult(result, record, message);
}
}
catch (ListenerExecutionFailedException e) { // NOSONAR ex flow control
if (this.errorHandler != null) {
try {
Object result = this.errorHandler.handleError(message, e, consumer);
if (result != null) {
handleResult(result, record, message);
}
}
catch (Exception ex) {
throw new ListenerExecutionFailedException(createMessagingErrorMessage(// NOSONAR stack trace loss
"Listener error handler threw an exception for the incoming message",
message.getPayload()), ex);
}
}
else {
throw e;
}
}
See RecordMessagingMessageListenerAdapter source code for more info.

Spring REST Exception - getting the response payload

I have the following:
The "400 Bad request" is converted to a ResourceAccessException in Spring.
Is there any way to retrieve the payload here? I want to send the "errorMessage" further up the call chain.
Code-wise the following is used to do the request:
public <T> T post(String url, Object request, Class<T> className) {
try {
return logEnhancedRestTemplate.postForObject(url, request, className);
} catch(RestClientException ex) {
throw handleErrors(ex, url);
}
}
It is in the "handleErrors" method I want to use the "errorMessage" from the body.
If you want to retrieve the message of an exception use the method getMessage().
In your specific example maybe is better if you catch a generic exception, since I suppose that every type of Runtime exception should call your method handleErrors(ex, url).
If this is the case, I suggest you to modify your code with:
public <T> T post(String url, Object request, Class<T> className) {
try {
return logEnhancedRestTemplate.postForObject(url, request, className);
} catch(Exception ex) {
throw handleErrors(ex, url);
}
}

netty issue when writeAndFlush called from different InboundChannelHandlerAdapter.channelRead

I've got an issue, for which I am unable to post full code (sorry), due to security reasons. The gist of my issue is that I have a ServerBootstrap, created as follows:
bossGroup = new NioEventLoopGroup();
workerGroup = new NioEventLoopGroup();
final ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addFirst("idleStateHandler", new IdleStateHandler(0, 0, 3000));
//Adds the MQTT encoder and decoder
ch.pipeline().addLast("decoder", new MyMessageDecoder());
ch.pipeline().addLast("encoder", new MyMessageEncoder());
ch.pipeline().addLast(createMyHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128).option(ChannelOption.SO_REUSEADDR, true)
.option(ChannelOption.TCP_NODELAY, true)
.childOption(ChannelOption.SO_KEEPALIVE, true);
// Bind and start to accept incoming connections.
channelFuture = b.bind(listenAddress, listenPort);
With createMyHandlerMethod() that basically returns an extended implementation of ChannelInboundHandlerAdapter
I also have a "client" listener, that listens for incoming connection requests, and is loaded as follows:
final String host = getHost();
final int port = getPort();
nioEventLoopGroup = new NioEventLoopGroup();
bootStrap = new Bootstrap();
bootStrap.group(nioEventLoopGroup);
bootStrap.channel(NioSocketChannel.class);
bootStrap.option(ChannelOption.SO_KEEPALIVE, true);
bootStrap.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addFirst("idleStateHandler", new IdleStateHandler(0, 0, getKeepAliveInterval()));
ch.pipeline().addAfter("idleStateHandler", "idleEventHandler", new MoquetteIdleTimeoutHandler());
ch.pipeline().addLast("decoder", new MyMessageDecoder());
ch.pipeline().addLast("encoder", new MyMessageEncoder());
ch.pipeline().addLast(MyClientHandler.this);
}
})
.option(ChannelOption.SO_REUSEADDR, true)
.option(ChannelOption.TCP_NODELAY, true);
// Start the client.
try {
channelFuture = bootStrap.connect(host, port).sync();
} catch (InterruptedException e) {
throw new MyException(“Exception”, e);
}
Where MyClientHandler is again a subclassed instance of ChannelInboundHandlerAdapter. Everything works fine, I get messages coming in from the "server" adapter, i process them, and send them back on the same context. And vice-versa for the "client" handler.
The problem happens when I have to (for some messages) proxy them from the server or client handler to other connection. Again, I am very sorry for not being able to post much code, but the gist of it is that I'm calling from:
serverHandler.channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof myProxyingMessage) {
if (ctx.channel().isActive()) {
ctx.channel().writeAndFlush(someOtherMessage);
**getClientHandler().writeAndFlush(myProxyingMessage);**
}
}
}
Now here's the problem: the bolded (client) writeAndFlush - never actually writes the message bytes, it doesn't throw any errors. The ChannelFuture returns all false (success, cancelled, done). And if I sync on it, eventually it times out for other reasons (connection timeout set within my code).
I know I haven't posted all of my code, but I'm hoping that someone has some tips and/or pointers for how to isolate the problem of WHY it is not writing to the client context. I'm not a Netty expert by any stretch, and most of this code was written by someone else. They are both subclassing ChannelInboundHandlerAdapter
Feel free to ask any questions if you have any.
*****EDIT*********
I tried to proxy the request back to a DIFFERENT context/channel (ie, the client channel) using the following test code:
public void proxyPubRec(int messageId) throws MQTTException {
logger.log(logLevel, "proxying PUBREC to context: " + debugContext());
PubRecMessage pubRecMessage = new PubRecMessage();
pubRecMessage.setMessageID(messageId);
pubRecMessage.setRemainingLength(2);
logger.log(logLevel, "pipeline writable flag: " + ctx.pipeline().channel().isWritable());
MyMQTTEncoder encoder = new MyMQTTEncoder();
ByteBuf buff = null;
try {
buff = encoder.encode(pubRecMessage);
ctx.channel().writeAndFlush(buff);
} catch (Throwable t) {
logger.log(Level.SEVERE, "unable to encode PUBREC");
} finally {
if (buff != null) {
buff.release();
}
}
}
public class MyMQTTEncoder extends MQTTEncoder {
public ByteBuf encode(AbstractMessage msg) {
PooledByteBufAllocator allocator = new PooledByteBufAllocator();
ByteBuf buf = allocator.buffer();
try {
super.encode(ctx, msg, buf);
} catch (Throwable t) {
logger.log(Level.SEVERE, "unable to encode PUBREC, " + t.getMessage());
}
return buf;
}
}
But the above at line: ctx.channel().writeAndFlush(buff) is NOT writing to the other channel - any tips/tricks on debugging this sort of issue?
someOtherMessage has to be ByteBuf.
So, take this :
serverHandler.channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof myProxyingMessage) {
if (ctx.channel().isActive()) {
ctx.channel().writeAndFlush(someOtherMessage);
**getClientHandler().writeAndFlush(myProxyingMessage);**
}
}
}
... and replace it with this :
serverHandler.channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof myProxyingMessage) {
if (ctx.channel().isActive()) {
ctx.channel().writeAndFlush(ByteBuf);
**getClientHandler().writeAndFlush(myProxyingMessage);**
}
}
}
Actually, this turned out to be a threading issue. One of my threads was blocked/waiting while other threads were writing to the context and because of this, the writes were buffered and not sent, even with a flush. Problem solved!
Essentially, I put the first message code in an Runnable/Executor thread, which allowed it to run separately so that the second write/response was able to write to the context. There are still potentially some issues with this (in terms of message ordering), but this is not on topic for the original question. Thanks for all your help!

Gmail API batch get support?

I am doing WEB HTTP calls using Gmail API. Is there a way to batch get message content?
It seems that messages.list only returns messageIds, and messages.get only support single message query.
LIST API: https://www.googleapis.com/gmail/v1/users/userId/messages
GET API: https://www.googleapis.com/gmail/v1/users/userId/messages/id
Help me guys~ Thank you!
You can definitely do batched messages.get(), quite a few questions covering it already:
https://stackoverflow.com/search?q=%5Bgmail-api%5D+batch
The gmail API returns only messageIds first to prevent heavy load.
With those Ids you can get individual full messages or send a batch request for getting a bunch of messages.
After getting the partialMessages(message ids) use this :
List<Messages> fullMessages = getFullyQualifiedMessages(partialMessages);
private List<Message> getFullyQualifiedMessages(List<Message> partialMessages) {
try {
final JsonBatchCallback<Message> callback = new JsonBatchCallback<Message>() {
public void onSuccess(Message message, HttpHeaders responseHeaders) {
fullyQualifiedMessageList.add(message);
}
public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) {
// do what you want if error occurs
}
};
BatchRequest batch = mService.batch();
for (Message message : partialMessages) {
mService.users().messages().get("me", message.getId()).setFormat("full").queue(batch, callback);
}
batch.execute();
} catch (IOException e) {
e.printStackTrace();
}
Log.d(TAG, "Message" + fullyQualifiedMessageList.size());
return fullyQualifiedMessageList;
}