Why would BizTalk 2016 kill custom pipeline component threads? - sftp

I have a BizTalk Custom Pipeline Component that writes an SFTP file (using SSH.net), triggered by an SFTP (WinSCP) receive location.
The code within the Retry occasionally (around half the time) does not hit either the "Success" nor the logging catch block and no further processing occurs within the Pipeline. I assume that means the thread has been destroyed.
I added the Retry code later to make it try a few times but with the thread being destroyed I don't always get a success or 3 failures.
What could cause this behaviour in BizTalk 2016?
public void Archive(byte[] content,
string archivePath,
string userName,
string password,
string serverAddress,
string sshHostKeyFingerprint)
{
Retry(3, () =>
{
try
{
using (var sftpClient = new SftpClient(serverAddress, userName, password))
{
if (!string.IsNullOrWhiteSpace(sshHostKeyFingerprint))
{
sshHostKeyFingerprint = sshHostKeyFingerprint.Split(' ').Last();
sftpClient.HostKeyReceived += delegate (object sender, HostKeyEventArgs e)
{
if (e.FingerPrint.SequenceEqual(ConvertFingerprintToByteArray(sshHostKeyFingerprint)))
e.CanTrust = true;
else
e.CanTrust = false;
};
}
sftpClient.Connect();
sftpClient.WriteAllBytes(archivePath, content);
sftpClient.Disconnect();
LogInfo($"Success");
}
}
catch (Exception exception)
{
// show the bad path for "No such file" errors
throw new InvalidOperationException($"Failed to create file '{archivePath}'", exception);
}
});
}
private void Retry(int maxAttempts, Action action)
{
int attempt = 1;
while (attempt <= maxAttempts)
{
try
{
action();
break; // success
}
catch (Exception exception)
{
LogWarning($"Attempt {attempt} Error: {exception.ToString()}");
if (attempt == maxAttempts)
throw; // final attempt exception propagated
}
finally
{
attempt++;
}
}
}

Related

JMS listener with netty TCP

I'm trying to develop Netty using TCP. I am using the IBM MQ client to connect to the MQ broker, and the idea is I need to develop a TCP server that receives a message passes it to MQ and if the server responds send it to the client that sent the request. Therefore, I need to implement a JMS listener for async message. The problem is that the JMS listener is outside of the Netty channel and I'm trying to figure out how to read the message add it to a Netty channel and send it immediately to the client connected to TCP socket. I can send messages perfectly. The problem is when the server responds. I receive the message, get the context/channel from the clientConnectionProvider and I writeAndFlush, but I don't see the message arrive at the client.
I create the listener in the main class.
public class Main {
private final Integer port;
private final Destination sendDestination;
private final JMSContext jmsSendContext;
private final JMSConsumer consumer;
private final JMSContext jmsRecieveContext;
private final Destination consumerDestination;
private final ClientConnectionProvider clientConnectionProvider;
public Main(Properties properties)
throws JMSException {
if (properties.containsKey(ConfigurationEnum.SERVER_PORT) {
this.port = properties.getProperty(ConfigurationEnum.SERVER_PORT)
} else {
log.error("server.port not defined in properties"
throw new ConfigException(
String.format("server.port not defined in properties");
}
JmsFactoryFactory ff = JmsFactoryFactory.getInstance(JmsConstants.WMQ_PROVIDER);
JmsConnectionFactory cf = ff.createConnectionFactory();
// Set the properties
cf.setStringProperty(CommonConstants.WMQ_HOST_NAME,
properties.getProperty(ConfigurationEnum.IBM_MQ_HOST.getValue()));
cf.setIntProperty(CommonConstants.WMQ_PORT,
Integer.parseInt(properties.getProperty(ConfigurationEnum.IBM_MQ_PORT.getValue())));
cf.setStringProperty(CommonConstants.WMQ_CHANNEL,
properties.getProperty(ConfigurationEnum.IBM_MQ_CHANNEL.getValue()));
cf.setIntProperty(CommonConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
cf.setStringProperty(CommonConstants.WMQ_QUEUE_MANAGER,
properties.getProperty(ConfigurationEnum.IBM_QUEUE_MANAGER.getValue()));
cf.setStringProperty(CommonConstants.WMQ_APPLICATIONNAME, "FIX Orchestra Gateway");
cf.setBooleanProperty(JmsConstants.USER_AUTHENTICATION_MQCSP, true);
cf.setStringProperty(JmsConstants.USERID, properties.getProperty(ConfigurationEnum.IBM_APP_USER.getValue()));
cf.setStringProperty(JmsConstants.PASSWORD, properties.getProperty(ConfigurationEnum.IBM_APP_PASS.getValue()));
clientConnectionProvider = new ClientConnectionProvider();
jmsRecieveContext = cf.createContext();
consumerDestination = jmsRecieveContext
.createQueue(properties.getProperty(ConfigurationEnum.IBM_QUEUE_CONSUMER.getValue()));
consumer = jmsRecieveContext.createConsumer(consumerDestination);
consumer.setMessageListener(new JMSMessageListener(clientConnectionProvider));
jmsRecieveContext.start();
jmsSendContext = cf.createContext();
sendDestination = jmsSendContext
.createQueue(properties.getProperty(ConfigurationEnum.IBM_QUEUE_TRANSACTION.getValue()));
}
public void start() throws InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(10);
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100).option(ChannelOption.SO_KEEPALIVE, Boolean.TRUE)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new DefaultChannelInitializer());
// Start the server.
ChannelFuture f = serverBootstrap.bind(port).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
jmsRecieveContext.stop();
jmsRecieveContext.close();
jmsSendContext.close();
}
}
public static void main(String[] args) throws InterruptedException {
Properties properties = new Properties();
try (InputStream inputStream = new FileInputStream(args[0])) {
properties.load(inputStream);
new Main(properties).start();
} catch (FileNotFoundException e) {
log.error("Properties file specified in path {} was not found.", args[0], e);
} catch (IOException e) {
log.error("There was an IO error.", e);
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ConfigException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The listener is a simple class.
#AllArgsConstructor
public class JMSMessageListener implements MessageListener {
private final ClientConnectionProvider clientConnectionProvider;
#Override
public void onMessage(Message message) {
try {
String messageString = message.getBody(String.class);
if (clientConnectionProvider.contains(ClientID.get(messageString))) {
ClientConnection cc = clientConnectionProvider.getConnection(ClientID.get(messageString));
if (cc.getCtx() == null) {
// TODO: Need to save message when client reconects
} else {
cc.getCtx().channel().write(messageString);
}
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
You should call writeAndFlush(...) and attach a ChannelFutureListener to the ChannelFuture returned to it. In the listener you can check if the write did succeed or fail (and if so print the exception). In your current code you only call write(...) which only put the message in the outboundbuffer of the Channel but not actually flush it to the socket.

HttpClient.SendAsync exeption : The underlying connection was closed: The connection was closed unexpectedly

I've got an asp.net core 2.0 web app (Running using Kestrel) with following controller :
public IActionResult GetUpdateList(string apiCode, int softwareId, [FromBody] List<SoftwareFile> updateFiles)
{
try
{
var stream = SoftwareUpdateFilesHandler.GetUpdateZipFileStream(updateFiles, softwareId);
return File(stream.BaseStream, "application/octet-stream", "UpdateFile");
}
catch (System.Exception ex)
{
return NotFound(ex.ToString());
}
}
and this code on my client :
public async static Task<byte[]> GetUpdateAsync(string apiCode, int softwareId, List<SoftwareFile> updatefiles)
{
try
{
StringContent content = null;
if (updatefiles != null && updatefiles.Count > 0)
{
content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(updatefiles));
content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
}
string address = $"{baseAddress}GetUpdate?softwareId={softwareId}";
HttpRequestMessage request = new HttpRequestMessage(new HttpMethod("POST"), address);
request.Content = content;
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
var responseContent = await response.Content.ReadAsByteArrayAsync();
return responseContent;
}
catch(Exception ex)
{
return null;
}
}
But when code reaches to httpClient.SendAsync code hangs and after a few seconds client app crashes and I get this exception : The underlying connection was closed: The connection was closed unexpectedly
All of this works fine when I test my code in local but when I publish code and try to call GetUpdateList I get exception.
Odd thing about this is I can't handle exception in my catch block. Somehow catch block doesn't catch this exception and I can see exception in application crash.

Can't return completedsuccesfull task in .net core

Hi I wrote the following code:
private bool GetIsCompleted()
{
return Email.SendMessageAsync().IsCompletedSuccessfully;
}
[HttpPost]
public ViewResult CheckOut(Order order)
{
if (Cart.Lines.Count() == 0)
{
ModelState.AddModelError("","Your Cart is empty!");
}
if (ModelState.IsValid)
{
order.CartLines = Cart.Lines;
order.DateTime = DateTime.Now;
order.TotalPrice = Cart.ComputeTotalValue();
if (Repository.SaveOrder(order))
{
if (User.Identity.Name != null)
{
Email.SetMessageBody(order.OrderID);
if (GetIsCompleted())
{
Cart.Clear();
return View("Completed");
}
}
}
ViewBag.Error = "An error Occured while sending you an email with the order details.";
return View(new Order());
}
else
{
ViewBag.Error = "An error Occured while trying to save your order. Please try again!";
return View(new Order());
}
}
public async Task SendMessageAsync()
{
this.Message = new MailMessage(this.MailFrom.ToString(), this.MailTo.ToString(), this.GetSubject(), this.GetMessageBody());
//Message.Dispose();
try
{
await this.Client.SendMailAsync(this.Message);
}
catch (Exception ex)
{
Logger.LogInformation("The Email couldn't send to the recipient");
}
}
I get
An error Occured while sending you an email with the order details.
in the View. I want GetIsCompleted() to return true to proceed the code. It is developed under .net core. I do not understand why IsCompletedSuccessfully() does not return true; Any suggestion?
The current flow of your code is this:
Start sending the e-mail.
Check if it is completed successfully, decide that it hasn't and return failure.
The e-mail completes sending.
You're awaiting the actual SendMailAsync(..) method, and that's great, but nothing awaits SendMessageAsync(...) so it immediately returns the incomplete task to the caller. Because there isn't enough time between starting to send the e-mail and checking if the task completed, the status will be false.
You need to use async all the way up. Change your method definition to be async:
public async Task<ViewResult> CheckOut(Order order)
Replace this code:
if (GetIsCompleted())
{
Cart.Clear();
return View("Completed");
}
with this:
try
{
await Email.SendMessageAsync();
Cart.Clear();
return View("Completed");
}
catch (Exception e)
{
// handle exception
}
It's worth noting that you'll only ever get an exception if the call to new MailMessage(...) fails because your try/catch block in SendMessageAsync is swallowing all other exceptions.

Jersey2 Client reuse not working AsyncInvoker

I am trying to reuse a Jersey2(Jersey 2.16) Client for async invocation. However after 2 requests, I see that the threads going into a waiting state, waiting on a lock. Since client creation is an expensive operation, I am trying to reuse the client in the async calls. The issue occurs only with ApacheConnectorProvider as the connector class. I want to use ApacheConnectorProvider, as I need to use a proxy and set SSL properties and I want to use PoolingHttpClientConnectionManager.
The sample code is given below:
public class Example {
Integer eventId = 0;
private ClientConfig getClientConfig()
{
ClientConfig clientConfig = new ClientConfig();
ApacheConnectorProvider provider = new ApacheConnectorProvider();
clientConfig.property(ClientProperties.REQUEST_ENTITY_PROCESSING,RequestEntityProcessing.BUFFERED);
clientConfig.connectorProvider(provider);
return clientConfig;
}
private Client createClient()
{
Client client = ClientBuilder.newClient(getClientConfig());
return client;
}
public void testAsyncCall()
{
Client client = createClient();
System.out.println("Testing a new Async call on thread " + Thread.currentThread().getId());
JSONObject jsonObject = new JSONObject();
jsonObject.put("value", eventId++);
invoker(client, "http://requestb.in/nn0sffnn" , jsonObject);
invoker(client, "http://requestb.in/nn0sffnn" , jsonObject);
invoker(client, "http://requestb.in/nn0sffnn" , jsonObject);
client.close();
}
private void invoker(Client client, String URI, JSONObject jsonObject)
{
final Future<Response> responseFuture = client.target(URI)
.request()
.async()
.post(Entity.entity(jsonObject.toJSONString(), MediaType.TEXT_PLAIN));
try {
Response r = responseFuture.get();
System.out.println("Response is on URI " + URI + " : " + r.getStatus());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String args[])
{
Example client1 = new Example();
client1.testAsyncCall();
return;
}
}
The response I see is:
Testing a new Async call on thread 1
Response is on URI http://requestb.in/nn0sffnn : 200
Response is on URI http://requestb.in/nn0sffnn : 200
On looking at the thread stack, I see the following trace:
"jersey-client-async-executor-0" prio=6 tid=0x043a4c00 nid=0x56f0 waiting on condition [0x03e5f000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x238ee148> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
at org.apache.http.pool.PoolEntryFuture.await(PoolEntryFuture.java:133)
at org.apache.http.pool.AbstractConnPool.getPoolEntryBlocking(AbstractConnPool.java:282)
at org.apache.http.pool.AbstractConnPool.access$000(AbstractConnPool.java:64)
at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:177)
at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:170)
Can someone give me a suggestion as to how to reuse Client objects for async requests and may be how to get over this issue as well.

Error for GetStringAsync if triggered by ScheduledAgent but no error during WP8 App usage

I have a wrapper for the webclient that I am using to retrieve some data. This same function is being used by the WP8 App and also used by the WP8 ScheduledAgent.
Somehow, when the function is used by the WP8 App, there is no error and it returns correctly.
However, when the ScheduledAgent uses the function, it erred out at the bold code below. I tried a try catch but it is not catching. Via Debugger, the GetSTringAsync(uri) had completed without any exception. The error seemed to be only happening when it is assigning the return Task to the result string.
The error I received is:
An unhandled exception of type 'System.UnauthorizedAccessException' occurred in System.Windows.ni.dll
public class HttpClient : WebClient
..
private async Task GetStringAsync(string strUri)
{
Uri uri = new Uri(strUri);
string result = string.Empty;
try
{
result = await GetStringAsync(uri);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return result;
}
...
private Task GetStringAsync(Uri requestUri)
{
TaskCompletionSource tcs = new TaskCompletionSource();
try
{
this.DownloadStringCompleted += (s, e) =>
{
if (e.Error == null)
{
tcs.TrySetResult(e.Result);
}
else
{
tcs.TrySetException(e.Error);
}
};
this.DownloadStringAsync(requestUri);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
if (tcs.Task.Exception != null)
{
throw tcs.Task.Exception;
}
return tcs.Task;
}
Please advise if I am missing something.
My problem is because I am using pushpin as one of my object types within my Model. Apparently, in the scheduled agent, it is not able to access that object type and thus threw the above error.

Resources