[Dbix-class] Proper way to suppress die from DBIx::Class

Lasse Makholm lasse at unity3d.com
Wed Oct 15 22:16:55 GMT 2014


On Wed, Oct 15, 2014 at 7:11 PM, Sean Quinlan <spq.easy at gmail.com> wrote:

> Thanks!
>
> I would have prefered to _not_ have to set unsafe, as it would be great if
> DBIC continued to handle exceptions internally as always, but just didn't
> pass the exception out after catching and handling it internally.
>
> And I appreciate the 'architecturally unsound' warning, and would agree
> in general. The only reason we're doing it this way is that we already have
> exception handling built in to the application. The idea here is not to
> just skip handling exceptions, but rather automate propagating exceptions
> up to the application level, without having to hand-wrap all calls in eval.
> So if handle_error in DBI calls our applications add_error() (_without_
> blocking or altering DBIC's), then the die on call is redundant, as the
> apps existing error handling will pick it up.
>

I'm really struggling to understand this reasoning, so forgive me if I come
across as telling you that you're doing it all wrong...

Surely exceptions are always propagated up through the call stack to the
nearest catch block and since DBIC does not catch exceptions for you, you
are free to put a try/catch pair as high or as low in the call stack as you
want. The whole point of structured exception handling is to let you put
error handling where you want it instead of around every call that might
possibly go wrong, no?

A try/catch pair in your dispatcher or entry point to your response handler
should be a trivial thing to implement and would take care of meaningful
responses in case of exceptions. Assuming no other try/catch pairs in the
code path for a given request, that would still, of course, abort execution
after the first error. But you want it to continue, right? Is that the crux
of the matter?

I guess you have your reasons wanting to do that but I can think of any
number of reasons (ranging from simply returning incorrect data to deleting
the wrong data or worse) why this approach is dangerous. And I guess that's
what Peter means by "architecturally unsound"...

Given a chunk of code that does multiple inserts/updates - do you really
want it to just blindly continue, even after something has gone wrong?

I'm curious about what sort of application would want that kind of
unsafe-by-default behaviour...


> Actually, if you wanted to encourage die or handle as an explicit decision
> and still discourage not handling it at all, perhaps a new optional
> argument to connect to provide a callback for external error handling,
> which when provided sets DBIC to not propagate fatal errors to the
> application? exception_action seemed to come close, but was triggered too
> often and did not suppress the die.
>

You probably know this already but in case you don't: With DBIC it's a
relatively trivial thing to create your own base class for all resultsets
and all result classes in your schema. In those two classes, overriding
insert(), update() and a handful of other methods would probably get you
what you want. It's of course more work than just flipping a switch in
DBIC, but it's a lot less work than changing every place you call into
DBIC. E.g. assuming a property on your schema that knows what to do with
exceptions, something like:

sub update
{
my $self = shift;
return try {
$self->next::method(@_);
} catch {
$self->result_source->schema->some_context_thingy->add_error($_);
};
}

/L

Please feel free to email me directly if there is anything I can do to help
> or questions I can answer. I'd also of course be happy to test any updates.
>
> -Cheers,
> Sean
>
> On Wed, Oct 15, 2014 at 12:01 PM, Peter Rabbitson <rabbit+dbic at rabbit.us>
> wrote:
>
>> On 10/15/2014 04:55 PM, Sean Quinlan wrote:
>>
>>> The end result I want is to not have to wrap every update / insert / etc
>>> with an eval.
>>>
>>> I have no problem if DBIC internals use exception-based control
>>> internally. I just want to optionally have it not bubble up to the level
>>> of my application. It would be far more elegant if I could have DBIC
>>> play nicely with our applications exception handling, rather than have
>>> to insulate every usage manually.
>>>
>>>
>> This is a reasonable (albeit architecturally unsound) request. If the
>> 'unsafe' handling is requested everything not happening in a transaction
>> should indeed not result in exceptions.
>>
>> In order to go forward with this I will need a modest set of lives_ok
>> checks for various operations. The actual implementation will be more
>> involved and will likely be carried out by me or another core contrib. For
>> a concise test example, take a look at
>> https://github.com/dbsrgits/dbix-class/blob/current/for_
>> cpan_index/t/schema/anon.t
>>
>> Let me know if you have any further questions
>>
>> Cheers!
>>
>>
>> _______________________________________________
>> List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
>> IRC: irc.perl.org#dbix-class
>> SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
>> Searchable Archive: http://www.grokbase.com/group/
>> dbix-class at lists.scsys.co.uk
>>
>
>
> _______________________________________________
> List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
> IRC: irc.perl.org#dbix-class
> SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
> Searchable Archive:
> http://www.grokbase.com/group/dbix-class@lists.scsys.co.uk
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.scsys.co.uk/pipermail/dbix-class/attachments/20141016/7b01c1b9/attachment-0001.htm>


More information about the DBIx-Class mailing list