Skip to content

Commit 9e7ee78

Browse files
Update incerceptor guidance
1 parent b53e3fe commit 9e7ee78

1 file changed

Lines changed: 51 additions & 16 deletions

File tree

docs/source-2.0/guides/client-guidance/interceptors.md

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ to only the properties that are relevant to that hook. This makes each hook
3131
easier to reason about, and helps to ensure that a change in execution order
3232
doesn't result in different behavior.
3333

34+
Hooks are intended to be lightweight, so blocking operations should not be
35+
supported.
36+
3437
### Hook sequence
3538

3639
The following is an ordered list of recommended hooks. It is also recommended to
@@ -86,24 +89,28 @@ protocols, these are HTTP requests and HTTP responses.
8689
8. **readAfterExecution** *(immutable)* — The last thing called during an
8790
execution.
8891

89-
### Error behavior
92+
### Error handling
93+
94+
Error handling behavior depends on where in the pipeline the hook is called and
95+
whether or not the hook is mutable.
96+
97+
#### Error accumulation
9098

91-
Errors raised in hooks are handled consistently. The behavior depends on where
92-
in the pipeline the hook is called:
99+
When an immutable hook is being executed, all interceptors are always invoked
100+
and any errors thrown by those interceptors are accumulated before any further
101+
action is taken. The last error thrown by an interceptor is re-thrown. If the
102+
language supports suppressed errors, the other errors should be suppressed. If
103+
not, the other errors should be logged and dropped. The may also be attached to
104+
the raised error as metadata.
93105

94-
- **Hooks called once per execution** (`readBeforeExecution`,
95-
`readAfterExecution`): Errors are collected across all interceptors before any
96-
further action is taken. If multiple interceptors raise errors, the last error
97-
wins and earlier ones are logged and dropped.
106+
When a mutable hook is being executed, the first error thrown is immediately
107+
forwarded on and no other interceptors are invoked.
98108

99-
- **Most other hooks**: An error immediately jumps execution to
100-
`modifyBeforeAttemptCompletion` (if inside the retry loop) or
101-
`modifyBeforeCompletion` (if outside), with the error set as the result.
109+
#### Control flow
102110

103-
- **`readAfterAttempt`**: Errors are collected the same way as
104-
`readBeforeExecution`. After all interceptors have been called, the
105-
[retry strategy](#client-guidance-retries) decides whether to retry or proceed
106-
to `modifyBeforeCompletion`.
111+
When an error is raised in a hook outside the retry loop, execution immediately
112+
jumps to `modifyBeforeCompletion`. When an error is raised outside the retry
113+
loop, execution immediately jumps to `modifyBeforeAttemptCompletion`.
107114

108115
## Interfaces
109116

@@ -138,7 +145,22 @@ public class ResponseHook<I, O, RequestT, ResponseT> extends RequestHook<I, O, R
138145
// Available from readAfterDeserialization and modifyBeforeAttemptCompletion onward.
139146
// Adds the deserialized output (may be null if the attempt failed).
140147
public class OutputHook<I, O, RequestT, ResponseT> extends ResponseHook<I, O, RequestT, ResponseT> {
141-
public O output() { ... }
148+
public Optional<O> output() { ... }
149+
150+
public Optional<RuntimeException> error() { ... }
151+
152+
/**
153+
* If an exception {@code e} is provided, throw it, otherwise return the output value.
154+
*
155+
* @param e Error to potentially rethrow.
156+
* @return the output value.
157+
*/
158+
public O forward(RuntimeException e) {
159+
if (e != null) {
160+
throw e;
161+
}
162+
return output;
163+
}
142164
}
143165
```
144166

@@ -213,6 +235,19 @@ public interface Interceptor {
213235
}
214236
```
215237

238+
:::{admonition} Error modeling
239+
:class: important
240+
241+
In these interfaces, errors are provided separately from the `OutputHook` type.
242+
This is a minor optimization that eliminates the need to allocate new `OutputHook`
243+
instances when errors are thrown.
244+
245+
In languages that have a native union type (such as Python) or a native `Result`
246+
type (such as Rust), the usability benefits of integrating the error into the
247+
`OutputHook` may be preferrable.
248+
249+
:::
250+
216251
## Example
217252

218253
The following interceptor adds a tracing header to HTTP requests when running
@@ -222,7 +257,7 @@ cause the signature to include the header. That would be fine, but this
222257
particular header is added after signing in practice.
223258

224259
```java
225-
public class AddTraceHeader implements ClientInterceptor {
260+
public class AddTraceHeader implements Interceptor {
226261
private final String traceId;
227262

228263
public AddTraceHeader(String traceId) {

0 commit comments

Comments
 (0)