HTTP entrypoint, handling error within a dependency?

I have an Auth dependency which adds `self.auth` to a nameko service with
user_id and some other details on it.

Upon a http request, it looks at the request passed into an entrypoint,
parses headers etc.

The issue I am having is that if there is something wrong with the headers,
it'll raise a `ValueError` with a message.

I have a decorator on my http entrypoint which catches `ValueError` and
returns a 400 http status code along with a message, however this doesn't
catch the ValueError when it's coming from the dependency.

The end result being a 500 error.

How can I deal with the error from the dependency, and return status
code/resp?

class MyService:
    auth = AuthDep()

   @handle_http_errors
   @http('GET', '/')
   def get_thing(self, request):
       return 200, 'thing'

Thanks

I've got a hacky solution to this:

class AuthDep:

    def get_dependency(self, worker_ctx):

     try:
         do_stuff_that_sometimes_raises():
     except ValueError as exc:
         return LazyDependencyException(exc=exc)

class LazyDependencyException:
    def __init__(self, exc):
        self.exc = exc

    def __getattr__(self, name):
        raise self.exc

    def __call__(self):
        raise self.exc

This just causes the exception to raise within the entrypoint when the
dependency is accessed.

Is this a terrible of an idea as it seems? Is there a better way to handle
an error within the dependency?

···

On Friday, June 16, 2017 at 3:37:50 PM UTC+1, Richard wrote:

I have an Auth dependency which adds `self.auth` to a nameko service with
user_id and some other details on it.

Upon a http request, it looks at the request passed into an entrypoint,
parses headers etc.

The issue I am having is that if there is something wrong with the
headers, it'll raise a `ValueError` with a message.

I have a decorator on my http entrypoint which catches `ValueError` and
returns a 400 http status code along with a message, however this doesn't
catch the ValueError when it's coming from the dependency.

The end result being a 500 error.

How can I deal with the error from the dependency, and return status
code/resp?

class MyService:
    auth = AuthDep()

   @handle_http_errors
   @http('GET', '/')
   def get_thing(self, request):
       return 200, 'thing'

Thanks

possibly less hacky is to instead of `LazyDependencyException` return a
sentinel object that your decorator could explicitly look for and bail out
early (similar to failed auth i guess).

best,
d

···

On Monday, 19 June 2017 10:36:41 UTC+1, Richard O'Dwyer wrote:

I've got a hacky solution to this:

class AuthDep:

    def get_dependency(self, worker_ctx):

     try:
         do_stuff_that_sometimes_raises():
     except ValueError as exc:
         return LazyDependencyException(exc=exc)

class LazyDependencyException:
    def __init__(self, exc):
        self.exc = exc

    def __getattr__(self, name):
        raise self.exc

    def __call__(self):
        raise self.exc

This just causes the exception to raise within the entrypoint when the
dependency is accessed.

Is this a terrible of an idea as it seems? Is there a better way to handle
an error within the dependency?

On Friday, June 16, 2017 at 3:37:50 PM UTC+1, Richard wrote:

I have an Auth dependency which adds `self.auth` to a nameko service with
user_id and some other details on it.

Upon a http request, it looks at the request passed into an entrypoint,
parses headers etc.

The issue I am having is that if there is something wrong with the
headers, it'll raise a `ValueError` with a message.

I have a decorator on my http entrypoint which catches `ValueError` and
returns a 400 http status code along with a message, however this doesn't
catch the ValueError when it's coming from the dependency.

The end result being a 500 error.

How can I deal with the error from the dependency, and return status
code/resp?

class MyService:
    auth = AuthDep()

   @handle_http_errors
   @http('GET', '/')
   def get_thing(self, request):
       return 200, 'thing'

Thanks

Sorry for the delayed reply.

The fundamental problem here is that worker setup (and dependency
injection) aren't handled inside the scope of a particular worker call. We
assume that any exception outside of the service method cannot be handled
and therefore we let it bubble out. It intentionally crashes the whole
process. This has been discussed on the mailing list before
<https://groups.google.com/forum/#!searchin/nameko-dev/worker$20setup|sort:relevance/nameko-dev/POBxAV71TUE/XRqyV-iHCwAJ> because
it's somewhat surprising.

Arguably worker_setup and get_dependency really can be attributed to a
particular worker and errors in these methods should be returned to the
client, rather than crashing the process. Dealing with errors in
worker_result and worker_teardown are slightly more tricky, since we've
already sent a response to the caller. But perhaps throwing a traceback and
recovering would be better than our current design. It would be more
in-line with what other frameworks do. It is a relatively easy change,
although obviously not backwards compatible.

An alternative approach would be to use a "contract" between the extensions
and explicitly ask the Auth dependency from the http entrypoint whether the
request is valid. All bound extensions have access to the container so this
is feasible, but it requires coupling your two extensions together, which
isn't very nice.

@David what are your thoughts on bringing these errors into the "worker
lifecycle"?

···

On Monday, June 19, 2017 at 11:10:50 AM UTC+1, David Szotten wrote:

possibly less hacky is to instead of `LazyDependencyException` return a
sentinel object that your decorator could explicitly look for and bail out
early (similar to failed auth i guess).

best,
d

On Monday, 19 June 2017 10:36:41 UTC+1, Richard O'Dwyer wrote:

I've got a hacky solution to this:

class AuthDep:

    def get_dependency(self, worker_ctx):

     try:
         do_stuff_that_sometimes_raises():
     except ValueError as exc:
         return LazyDependencyException(exc=exc)

class LazyDependencyException:
    def __init__(self, exc):
        self.exc = exc

    def __getattr__(self, name):
        raise self.exc

    def __call__(self):
        raise self.exc

This just causes the exception to raise within the entrypoint when the
dependency is accessed.

Is this a terrible of an idea as it seems? Is there a better way to
handle an error within the dependency?

On Friday, June 16, 2017 at 3:37:50 PM UTC+1, Richard wrote:

I have an Auth dependency which adds `self.auth` to a nameko service
with user_id and some other details on it.

Upon a http request, it looks at the request passed into an entrypoint,
parses headers etc.

The issue I am having is that if there is something wrong with the
headers, it'll raise a `ValueError` with a message.

I have a decorator on my http entrypoint which catches `ValueError` and
returns a 400 http status code along with a message, however this doesn't
catch the ValueError when it's coming from the dependency.

The end result being a 500 error.

How can I deal with the error from the dependency, and return status
code/resp?

class MyService:
    auth = AuthDep()

   @handle_http_errors
   @http('GET', '/')
   def get_thing(self, request):
       return 200, 'thing'

Thanks