Why does SignalR recommend using finally to propagate errors in streams? - asp.net-core

The SignalR docs on streaming state:
Wrap logic in a try ... catch statement. Complete the Channel in a finally block. If you want to flow an error, capture it inside the catch block and write it in the finally block.
They then proceed to give an example that goes through these convolutions for no apparent gain. Why is this? What difference does it make whether one captures an exception and completes the channel from the finally block versus completing then and there in the catch block?

Possibly to centralize the writer completion logic, even if takes just a single invocation - and you may want to insert additional related logic there (such as logging), if needed.
Exception localException = null;
try
{
// ...
}
catch (Exception ex)
{
localException = ex;
}
finally
{
writer.Complete(localException);
}
versus:
var completed = false;
try
{
// ...
}
catch (Exception ex)
{
writer.Complete(ex);
completed = true;
}
finally
{
if (!completed)
{
writer.Complete(null);
}
}

Related

Cannot handle exception in firebase function

i'm trying to understand with no luck why this throwable is not catched in my catch block:
CoroutineScope(IO).launch {
try { FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
if (task.isSuccessful) {
token = task.result
}
throw Exception("Hi There!")
}).await()
getUsers().await()
}catch (e: Exception){
binding.txtTitle.text = "Error: ${e.message}"
}
}
The exception is called but the app crash and not handle by the catch block. But if i throw an exception outside the addOnCompleteListener the exception is handled normally. My objective is to stop the execution of the getUsers function if no token is available.
The exception which is thrown in OnCompleteListener will not propagate to the outer scope, it is scoped to OnCompleteListener block. To achieve your objective I would recommend to rewrite the code to something like the following:
coroutineScope.launch {
try {
val token: String = FirebaseMessaging.getInstance().token.await()
if (token.isNotEmpty) {
getUsers().await()
}
} catch (e: Exception){
// ...
}
}
await function waits for task to complete.

How to verify exception thrown using StepVerifier in project reactor

def expectError() {
StepVerifier.create(readDB())
.expectError(RuntimeException.class)
.verify();
}
private Mono<String> readDB() {
// try {
return Mono.just(externalService.get())
.onErrorResume(throwable -> Mono.error(throwable));
// } catch (Exception e) {
// return Mono.error(e);
// }
}
unable to make it work if externalService.get throws Exception instead of return Mono.error. Is is always recommended to transform to Mono/Flow using try catch or is there any better way to verify such thrown exception?
Most of the time, if the user-provided code that throws an exception is provided as a lambda, exceptions can be translated to onError. But here you're directly throwing in the main thread, so that cannot happen

What is the cleanest way to listen to JMS from inside a Spring-batch step?

Spring batch documentation recommends using the JmsItemReader, which is a wrapper around the JMSTemplate. However, I have discovered that the JMSTemplate has some issues - see http://activemq.apache.org/jmstemplate-gotchas.html .
This post came to my attention only because the queue was appearing to disappear before I could actually read the data of of it. The opportunity to miss messages seems like a fairly significant issue to me.
For consumers atleast try using DefaultMessageListenerContainer coupled with a SingleConnectionFactory or any such connection factory , it not need a scheduler to wake them up.there are log of examples explaining this , this one is really good in explaining stuff
http://bsnyderblog.blogspot.com/2010/05/tuning-jms-message-consumption-in.html
Here is the solution I ended up with. Since the query was about the "cleanest" way to listen to JMS from within a spring-batch step, I'm going to leave the question open for a while longer just in case there's a better way.
If someone can figure out why the code isn't formatting correctly, please let me know how to fix it.
1. In the a job listener, implement queue setup and teardown inside the beforeJob and afterJob events, respectively:
public void beforeJob(JobExecution jobExecution) {
try {
jobParameters = jobExecution.getJobParameters();
readerConnection = connectionFactory.createConnection();
readerConnection.start();
} catch (JMSException ex) {
// handle the exception as appropriate
}
}
public void afterJob(JobExecution jobExecution) {
try {
readerConnection.close();
} catch (JMSException e) {
// handle the exception as appropriate
}
}
2. In the reader, implement the StepListener and beforeStep / afterStep methods.
public void beforeStep(StepExecution stepExecution) {
this.stepExecution = stepExecution;
this.setJobExecution(stepExecution.getJobExecution());
try {
this.connection = jmsJobExecutionListener.getReaderConnection();
this.jmsSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
this.messageConsumer = jmsSession.createConsumer(jmsJobExecutionListener.getQueue());
}
catch (JMSException ex)
{
// handle the exception as appropriate
}
}
public ExitStatus afterStep(StepExecution stepExecution) {
try {
messageConsumer.close();
jmsSession.close();
} catch (JMSException e) {
// handle the exception as appropriate
}
return stepExecution.getExitStatus();
}
3. Implement the read() method:
public TreeModel<SelectedDataElementNode> read() throws Exception,
UnexpectedInputException, ParseException,
NonTransientResourceException {
Object result = null;
logger.debug("Attempting to receive message on connection: ", connection.toString());
ObjectMessage msg = (ObjectMessage) messageConsumer.receive();
logger.debug("Received: {}", msg.toString());
result = msg.getObject();
return result;
}
4. Add the listeners to the Spring Batch context as appropriate:
<batch:job id="doStuff">
<batch:listeners>
<batch:listener ref="jmsJobExecutionListener" />
</batch:listeners>
... snip ...
<batch:step id="step0003-do-stuff">
<batch:tasklet transaction-manager="jtaTransactionManager"
start-limit="100">
<batch:chunk reader="selectedDataJmsReader" writer="someWriter"
commit-interval="1" />
</batch:tasklet>
<batch:listeners>
<batch:listener ref="selectedDataJmsReader" />
</batch:listeners>
</batch:step>
</batch:job>

Handle error for request future calls in volley

I am making synchronous api calls using RequestFuture provided by Volley library.
I need to handle error response when in case the status code is 4xx/500.
try {
JSONObject response = future.get();
} catch (InterruptedException e) {
// exception handling
} catch (ExecutionException e) {
// exception handling
}
Now the error is caught by ExecutionException catch clause. How do I get NetworkResponse from this error.
How to override onErrorListener in the catch clause.
Try this for grabbing the error from volley. Also just a note when preforming future requests you should use get with a timeout so your not waiting forever.
try
{
JSONObject response = future.get(30,TimeUnit.SECONDS);
}
catch(InterruptedException | ExecutionException ex)
{
//check to see if the throwable in an instance of the volley error
if(ex.getCause() instanceof VolleyError)
{
//grab the volley error from the throwable and cast it back
VolleyError volleyError = (VolleyError)ex.getCause();
//now just grab the network response like normal
NetworkResponse networkResponse = volleyError.networkResponse;
}
}
catch(TimeoutException te)
{
Log.e(TAG,"Timeout occurred when waiting for response");
}

Nhibernate: Handling an ITransaction Exception So That New Transactions Can Continue with same ISession

I have a list of 10 data objects that I want to insert/update to the database using NHibernate. If one throws an exception (say a primary key violation) I want to still insert/update the other 9. I rolled each object operation into its own atomic transaction, and roll back the transaction if there is an exception. Problem is that if a transaction does cause an exception and is rolled back, on the next transaction Nhibernate complains with the error: null id in Nexus.Data.PortfolioCorporateEntity entry (don't flush the Session after an exception occurs)
My main program is simple. It creates a session from a sessionfactory, creates the data access layer, does some work on the data objects and then tries to persist those data objects to the database.
sessionsManager = new NHibernateSessionManager();
session = sessionsManager.GetSession();
DALC = new NHibernateDataProvider(session);
…
foreach (var pce in pces)
{
try
{
DALC.UpdateOrAddObject<PortfolioCorporateEntity>(pce);
}
catch (Exception ex)
{
Console.WriteLine("Could not add Corporate Entity ID " + pce.CorporateEntity.CorporateEntityID.ToString());
}
}
This is the updateOrAdd procedure in my Nhibernate Data Access Layer, called 10 times for 10 objects.
public void UpdateOrAddObject<T>(T workObject)
{
using (ITransaction tx = mSession.BeginTransaction) {
try {
mSession.SaveOrUpdate(workObject);
mSession.Flush();
tx.Commit();
}
catch (Exception ex) {
tx.Rollback();
throw;
}
}
}
Just to make the point clear, the session is instantiated by the calling program and passed to the Data Access Layer object, constructor of which is below.
public NHibernateDataProvider(ISession session)
{
mSession = session;
}
This works fine except after the exception, it says don’t flush the session after exception. I’m not sure why – transaction was rolled back nicely and the database should be ready to accept another transaction no? What am I doing wrong?
It's not possible to re-use an NHibernate session after an exception is thrown. Quoting the documentation:
If the ISession throws an exception you should immediately rollback the
transaction, call ISession.Close() and discard the ISession instance.
Certain methods of ISession will not leave the session in a consistent state.
So the answer is that you can't do what you're trying to do. You need to create a new session and re-try the updates there.
I clear the session and it continues normally
ISession session = NHibernateHelper.Session;
using (ITransaction transaction = session.BeginTransaction())
{
try
{
session.Update(user, user.UserID);
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
session.Clear();
throw new DALException("Cannot update user", ex);
}
}
Thanks for the response. Just wanted to make sure it's done right. What you're saying is that my error handling should be simply changed to:
foreach (var pce in pces)
{
try
{
DALC.UpdateOrAddObject<PortfolioCorporateEntity>(pce);
}
catch (Exception ex)
{
Console.WriteLine("Could not add Corporate Entity ID " + pce.CorporateEntity.CorporateEntityID.ToString());
session.Close();
session = sessionsManager.GetSession();
DALC.Session = session;
}
}
Looks like this works just fine. Thanks.