What exceptions / temp problems?
The UoW is your actual POCOs, btw
How would you recover from any exception?
Think about how should that work in real code?Now there are, you say, 15 different exceptions, how would your response to these exceptions differ when there was one generic ravenexception? You would (or really should) still handle that exception accordingly to say an errorcode or inner exception, which brings you back to handle the 15 different situations. Thus the generic exception did not really solve the problem at hand.
There is no RavenException.There is some internal error handling, but in general, the rule is. If you got an exception from the RavenDB session, that session is toast. Its state is no longer valid, and the only method that you can call on it is dispose.In general, you'll see three types of exceptions:* Network errors - server unreachable, etc.* Concurrency errors - someone modified the doc* Just plain errors - you tried to do something not possible. (document key too long, etc).None of them are really things that you can recover from.
On Mon, Apr 16, 2012 at 11:38 PM,
Hello
catch(Exception e) {}
On Tue, Apr 17, 2012 at 5:59 PM, aa
Hi
// Ryan
This is one example of session usage:
------------------------------------------------------------------------------------------------------------------------------------------------------
[HttpOperation(HttpMethod.POST, ForUriName = "Execute")]
public OperationResult Execute(String operationId)
{
_logger.Info(String.Format
("Operation Manager: Adding a new task to the database for Operation with Id ({0})...",
operationId));
var session = _documentStore.OpenSession();
try
{
Operation operation = session.Get<Operation>(operationId);
Task task = session.CreateTaskFromOperation();
session.Store(task);
session.SaveChanges();
//Initiate Saga to control the task execution lifetime
Bus.SendLocal(new BeginTask() { TaskId = task.Id });
TaskDto taskDto = Mapper.Map<Task, TaskDto>(task);
return new OperationResult.OK(taskDto);
}
catch (InvalidOperationException invalidOperationException)
{
//Tried to create a task from an operation marked as inactive
_logger.Error(invalidOperationException.Message,invalidOperationException);
return new OperationResult.BadRequest()
{
ResponseResource =
new RestApiErrorReply()
{
MainDescription = invalidOperationException.Message,
ExceptionDetail = invalidOperationException.ToString()
}
};
}
finally
{
session.Dispose();
}
}
Could you post an example how you recover from session exceptions
right now in your code?// Ryan
public OperationResult Execute(String operationId)
{
_logger.Info(String.Format("Operation Manager: Adding a new task to
the database for Operation with Id ({0})...", operationId));
using(var session = _documentStore.OpenSession())
{
try
{
Operation operation = session.Get<Operation>(operationId);
Task task = session.CreateTaskFromOperation();
session.Store(task);
session.SaveChanges();
Bus.SendLocal(new BeginTask() { TaskId = task.Id });
TaskDto taskDto = Mapper.Map<Task, TaskDto>(task);
return new OperationResult.OK(taskDto);
}
catch (Exception e)
{
_logger.Error(e.Message,e);
if !(e is InvalidOperationException) ? return new
OperationResult.InternalServerError() :
return new OperationResult.BadRequest()
{
ResponseResource = new RestApiErrorReply()
{
MainDescription = e.Message,
ExceptionDetail = e.ToString()
}
};
}
}
}
What bothers me now is that your code assumes that only
session.CreateTaskFromOperation could throw an
InvalidOperationException,
while in a few months from now it could be possible that other lines
are throwing InvalidOperationException as well ...
I would rather see the try catch wrapped on session.CreateTaskFromOperation.
All other exceptions would be logged and a runtime error response
would be returned.
I say 'recover' since you do not only catch the exception but you also
handle it, that is, you do not rethrow the exception, effectively you
have swallowed it.
// Ryan
(I'm a VB guy so please excuse the VB.Net code)
Public Class RavenException
Inherits DataException
Public Sub New(msg As String, innerEx As Exception)
MyBase.New(String.Format("An exception what thrown from RavenDB
while tyrying to {0}",msg), innerEx)
End Sub
End Class
Then wrap all calls to the Raven session in their own try catch blocks like this
Public Sub DoSomeWork()
Try
' do some stuff
Try
' do some stuff with raven
Catch ex As Exception
Throw New RavenException("do some work.", ex)
End Try
Catch ex As RavenException
'log the RavenException and/or show the user a message
Catch ex As WhateverTypeOfExceptionsYouWantToHandle
' start handling non-raven exceptions
End Try
End Sub
--
Bryan Johns
K4GDW
http://www.greendragonweb.com
Do not meddle in the affairs of dragons, for you are crunchy and taste
good with ketchup.
But how do you know that you really can continue with your app when an
exception is thrown from a ravensession had it thrown a generic
ravenexception?
// Ryan
You can handle exceptions in a base controller class or in a filterattribute
so you do not have to sprinkle try catch every where.
But how do you know that you really can continue with your app when an
exception is thrown from a ravensession had it thrown a generic
ravenexception?
// Ryan
In the meantime, we're left with dealing with that ourselves. Another
way would be to use some form of method interception to wrap all raven
activities inside an implicit try-catch block that throws a custom
exception. PostSharp comes to mind. Another option would be to use
an IOC container that supports interception. I know that Unity and
Castle.Windsor both have this capability.
--
Bryan Johns
K4GDW
http://www.greendragonweb.com
Do not meddle in the affairs of dragons, for you are crunchy and taste
good with ketchup.
This example catches InvalidOperation to handle "Tried to create a
task from an operation marked as inactive"
I think you should explicitly check for this instead of using an
exception to control this state. If that is the case, exceptions
thrown from raven are suddenly not that 'important' anymore ...
// Ryan
What I think the OP is looking for is a way to easily identify exceptions
raised from Raven without sprinkling nested try-catch blocks all over his
code so that he can treat them differently in some way. This capability
has value even if it's nothing more than logging and re-throwing them.
--
Bryan Johns
K4GDW
"Where is the wisdom?
Lost in the knowledge.
Where is the knowledge?
Lost in the information. -- T. S. Eliot
Where is the information?
Lost in the data.
Where is the data?
Lost in the ***** database!-- Joe Celko"
(http://www.sqlservercentral.com/articles/Database+Design/72612/)
> -----Original Message-----
> From: rav...@googlegroups.com [mailto:rav...@googlegroups.com] On
> Behalf Of Ryan Heath
> Sent: Thursday, April 19, 2012 3:21 AM
> To: rav...@googlegroups.com
> Subject: Re: [RavenDB] Exception Handling in RavenDb UnitOfWork
>
> Looking again at your example, it seems you are struggling with
> exceptions from raven because you use exceptions to control flow?
>
> This example catches InvalidOperation to handle "Tried to create a task
> from an operation marked as inactive"
> I think you should explicitly check for this instead of using an
> exception to control this state. If that is the case, exceptions thrown
> from raven are suddenly not that 'important' anymore ...
>
> // Ryan
>
> On Tue, Apr 17, 2012 at 7:50 PM, aa <albert...@gmail.com> wrote:
> > This is one example of session usage:
> >
> > ---------------------------------------------------------------------
> -
> > ---------------------------------------------------------------------
> -
> > ----------
> >
> >
> > á[HttpOperation(HttpMethod.POST, ForUriName = "Execute")]
> >
> > á á á á public OperationResult Execute(String operationId)
> >
> > á á á á {
> >
> > á á á á á á _logger.Info(String.Format
> >
> > á á á á á á á á ("Operation Manager: Adding a new task to the
> database
> > for Operation with Id ({0})...",
> >
> > á á á á á á á á operationId));
> >
> >
> > á á á á á á var sessioná=á_documentStore.OpenSession();
> >
> > á á á á á á try
> >
> > á á á á á á {
> >
> > á á á á á á á á Operation operation =
> > session.Get<Operation>(operationId);
> >
> > á á á á á á á á Task task =ásession.CreateTaskFromOperation();
> >
> >
> > á á á á á á á áásession.Store(task);
> >
> >
> > á á á á á á á áásession.SaveChanges();
> >
> >
> > á á á á á á á á //Initiate Saga to control the task execution
> lifetime
> >
> > á á á á á á á á Bus.SendLocal(new BeginTask() { TaskId = task.Id });
> >
> >
> >
> > á á á á á á á á TaskDto taskDto = Mapper.Map<Task, TaskDto>(task);
> >
> >
> > á á á á á á á á return new OperationResult.OK(taskDto);
> >
> >
> > á á á á á á }
> >
> > á á á á á á catch (InvalidOperationException
> > invalidOperationException)
> >
> > á á á á á á {
> >
> > á á á á á á á á //Tried to create a task from an operation marked as
> > inactive
> >
> >
> >
> _logger.Error(invalidOperationException.Message,invalidOperationExcept
> > ion);
> >
> > á á á á á á á á return new OperationResult.BadRequest()
> >
> > áá á á á á á á á á á á á á {
> >
> > áá á á á á á á á á á á á á á á ResponseResource =
> >
> > áá á á á á á á á á á á á á á á á á new RestApiErrorReply()
> >
> > áá á á á á á á á á á á á á á á á á á á {
> >
> > áá á á á á á á á á á á á á á á á á á á á á MainDescription =
> > invalidOperationException.Message,
> >
> > áá á á á á á á á á á á á á á á á á á á á á ExceptionDetail =
> > invalidOperationException.ToString()
> >
> > áá á á á á á á á á á á á á á á á á á á }
> >
> > áá á á á á á á á á á á á á };
> >
> >
> >
> > á á á á á á }
> >
> >
> >
> > á á á á á á finally
> >
> > á á á á á á {
> >
> > á á á á á á á á session.Dispose();
> >
> > á á á á á á }
> >
> > á á á á }
> >
> > ---------------------------------------------------------------------
> -
> > ---------------------------------------------------------------------
> -
> > ---------------------------------------------------------------------
> -
> > ---------------
> >
> >
> > I need to catch DB related errors somewhere, I need to catch them NOT
> > to recover from them , I need to catch them to be able to LOG them
> and
> > send that proper error reply back. áIf I dont catch them there will
> be
> > an unhandled exception and the application will crash.
> >
> > This is not running on IIS, is a Windows service and the DB is
> Embedded.
> >
> > On Tuesday, April 17, 2012 12:40:52 PM UTC-5, Ryan Heath wrote:
> >>
> >> Could you post an example how you recover from session exceptions
> >> right now in your code?
> >>
> >> // Ryan
> >>
> >> On Tue, Apr 17, 2012 at 7:28 PM, aa áwrote:
> >>
> >>
> >> > If I dont catch these exceptions the application crashes.
> áCatching
> >> > (Exception) is way to broad. áThere must be a middle ground.
> >> >>>>> that Raven throws, it would be reallyácumbersomeáto catch all
// Ryan
Really?What happen when we get a OutOfMemoryException ? Should we wrap it?
In general, you are working with persistent storage, you have very few options of how to actually handle an error. Basically, abort the transaction and try again.
If you have expected errors in the model, you catch and handle that, but that is about it.You shouldn't be trying to handle ravendb errors, you just don't have a way to do that, in most scenarios.
How do you handle this?
On Thursday, April 19, 2012 10:52:43 AM UTC-4, aa wrote:How do you handle this?
Honestly you don't. You log it and move on.
If you want to truly be able "handle" real exceptions you want to look at using an Event Store and/or a Enterprise Service Bus so that you can reply full sequences, send correcting messages etc. If you don't want or can't have a ESB and/or an Event store you're tilting at windmills.
I would hope for a way to distinguish the difference between those
types of errors that could be fixed by an administrator so that I
could send a notification then display a friendly, apologetic message
to the user. Others errors that really can't be recovered from should
be logged, the session disposed, then either retry or move on to the
next transaction with a new session.