Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tapErrorZIO and tapErrorCauseZIO to Route and Routes #2755

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

tjarvstrand
Copy link

@tjarvstrand tjarvstrand commented Mar 30, 2024

Useful for things like error logging or reporting to external services such as Sentry.

@codecov-commenter
Copy link

codecov-commenter commented Mar 30, 2024

Codecov Report

Attention: Patch coverage is 0% with 10 lines in your changes are missing coverage. Please review.

Project coverage is 64.34%. Comparing base (709b459) to head (006b320).

Files Patch % Lines
...io-http/shared/src/main/scala/zio/http/Route.scala 0.00% 8 Missing ⚠️
...o-http/shared/src/main/scala/zio/http/Routes.scala 0.00% 2 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2755      +/-   ##
==========================================
- Coverage   64.42%   64.34%   -0.08%     
==========================================
  Files         148      148              
  Lines        8668     8678      +10     
  Branches     1589     1545      -44     
==========================================
  Hits         5584     5584              
- Misses       3084     3094      +10     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

self match {
case Provided(route, env) => Provided(route.tapErrorCauseZIO(f), env)
case Augmented(route, aspect) => Augmented(route.tapErrorCauseZIO(f), aspect)
case Handled(routePattern, handler, location) => Handled(routePattern, handler, location)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iirc, ensures handled that the typed error is handled. But a cause (defect) might still happen. So I think there should be a tap on the handler here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't seem to work as the Handled.handler's failure type is Response whereas f's failure type is Err which is not necessarily a Response.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can catch the Cause[Err], and if it contains an Err, then you rethrow it. But if it's really a Cause[Nothing], i.e. pure defect, without an Err inside it, then you can allow that to be caught by f, since f can handle those (Cause[Nothing] is a subtype of Cause[Err]).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tjarvstrand This does need to be fixed, and then will be good to merge!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, busy week! :/

I've been struggling a bit with the error case of f which, unless I'm mistaken, must be a Response. Does something like this make sense?

/**
   * Effectfully peeks at the unhandled failure cause of this Route.
   */
  final def tapErrorCauseZIO[Err1 >: Err](
    f: Cause[Err] => ZIO[Any, Err1, Any],
  )(implicit trace: Trace): Route[Env, Err1] =
    self match {
      case Provided(route, env)                        => Provided(route.tapErrorCauseZIO(f), env)
      case Augmented(route, aspect)                    => Augmented(route.tapErrorCauseZIO(f), aspect)
      case Handled(routePattern, handler, location)    =>
        Handled(
          routePattern,
          handler.tapErrorCauseZIO {
            case cause0: Cause[Err] => f(cause0).catchAllCause(cause => ZIO.fail(Response.fromCause(cause)))
            case _                  => ZIO.unit
          },
          location,
        )
      case Unhandled(rpm, handler, zippable, location) =>
        Unhandled(rpm, handler.tapErrorCauseZIO(f), zippable, location)
    }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you get cause0, do errorOrCause, and if it's an error, you have to refail that, but if it's a Cause[Nothing], you can feed it to f.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm slow, but shouldn't handler.tapErrorCauseZIO leave the error channel of the original effect intact so that I don't have to refail it?

Not trying to be difficult. I just want to make sure I understand what's going on.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, of course! Forgot the point of this function, which is tapping not recovering. 🤦‍♂️

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Tried to move too fast and now the build is failing. I'll have another look at this as soon as I can.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid I think I'm in need of some assistance.

There are warnings in Scala 3 (which I have actually not used yet):

[warn] -- Unchecked Warning: /Users/tjarvstrand/src/zio-http/zio-http/shared/src/main/scala/zio/http/Route.scala:134:17
[warn] 134 |            case err: Fail[Err] => f(err.value).catchAllCause(cause => ZIO.fail(Response.fromCause(cause)))
[warn]     |                 ^
[warn]     |the type test for zio.Cause.Fail[Err] cannot be checked at runtime because its type arguments can't be determined from zio.Cause[zio.http.Response]

I'm assuming this is related to type erasure somehow, but I'm not sure why there's no warning in Scala 2. Any tips on how to proceed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants