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

Refactor and improve fallback support for @SentinelResource annotation #693

Merged
merged 2 commits into from
Apr 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,27 @@
*/
String fallback() default "";

/**
* The {@code defaultFallback} is used as the default universal fallback method.
* It should not accept any parameters, and the return type should be compatible
* with the original method.
*
* @return name of the default fallback method, empty by default
* @since 1.6.0
*/
String defaultFallback() default "";

/**
* The {@code fallback} is located in the same class with the original method by default.
* However, if some methods share the same signature and intend to set the same fallback,
* then users can set the class where the fallback function exists. Note that the shared fallback method
* must be static.
*
* @return the class where the fallback method is located (only single class)
* @since 1.6.0
*/
Class<?>[] fallbackClass() default {};

/**
* @return the list of exception classes to trace, {@link Throwable} by default
* @since 1.5.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
Expand All @@ -31,8 +33,16 @@ public class DemoController {
private TestService service;

@GetMapping("/foo")
public String foo() throws Exception {
public String apiFoo(@RequestParam(required = false) Long t) throws Exception {
if (t == null) {
t = System.currentTimeMillis();
}
service.test();
return service.hello(System.currentTimeMillis());
return service.hello(t);
}

@GetMapping("/baz/{name}")
public String apiBaz(@PathVariable("name") String name) {
return service.helloAnother(name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
public final class ExceptionUtil {

public static void handleException(BlockException ex) {
// Handler method that handles BlockException when blocked.
// The method parameter list should match original method, with the last additional
// parameter with type BlockException. The return type should be same as the original method.
// The block handler method should be located in the same class with original method by default.
// If you want to use method in other classes, you can set the blockHandlerClass
// with corresponding Class (Note the method in other classes must be static).
System.out.println("Oops: " + ex.getClass().getCanonicalName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ public interface TestService {
void test();

String hello(long s);

String helloAnother(String name);
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,35 @@ public void test() {
}

@Override
@SentinelResource(value = "hello", blockHandler = "exceptionHandler")
@SentinelResource(value = "hello", fallback = "helloFallback")
public String hello(long s) {
if (s < 0) {
throw new IllegalArgumentException("invalid arg");
}
return String.format("Hello at %d", s);
}

public String exceptionHandler(long s, BlockException ex) {
@Override
@SentinelResource(value = "helloAnother", defaultFallback = "defaultFallback",
exceptionsToIgnore = {IllegalStateException.class})
public String helloAnother(String name) {
if (name == null || "bad".equals(name)) {
throw new IllegalArgumentException("oops");
}
if ("foo".equals(name)) {
throw new IllegalStateException("oops");
}
return "Hello, " + name;
}

public String helloFallback(long s, Throwable ex) {
// Do some log here.
ex.printStackTrace();
return "Oops, error occurred at " + s;
}

public String defaultFallback() {
System.out.println("Go to default fallback");
return "default_fallback";
}
}
23 changes: 14 additions & 9 deletions sentinel-extension/sentinel-annotation-aspectj/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,31 @@ The `@SentinelResource` annotation indicates a resource definition, including:

- `value`: Resource name, required (cannot be empty)
- `entryType`: Resource entry type (inbound or outbound), `EntryType.OUT` by default
- `fallback`: Fallback method when degraded (optional). The fallback method should be located in the same class with original method. The signature of the fallback method should match the original method (parameter types and return type).
- `blockHandler`: Handler method that handles `BlockException` when blocked. The signature should match original method, with the last additional parameter type `BlockException`. The block handler method should be located in the same class with original method by default. If you want to use method in other classes, you can set the `blockHandlerClass` with corresponding `Class` (Note the method in other classes must be *static*).
- `exceptionsToTrace`: List of business exception classes to trace and record (since 1.5.1).
- `fallback` (refactored since 1.6.0): Fallback method when exceptions caught (including `BlockException`, but except the exceptions defined in `exceptionsToIgnore`). The fallback method should be located in the same class with original method by default. If you want to use method in other classes, you can set the `fallbackClass` with corresponding `Class` (Note the method in other classes must be *static*). The method signature requirement:
- The return type should match the origin method;
- The parameter list should match the origin method, and an additional `Throwable` parameter can be provided to get the actual exception.
- `defaultFallback` (since 1.6.0): The default fallback method when exceptions caught (including `BlockException`, but except the exceptions defined in `exceptionsToIgnore`). Its intended to be a universal common fallback method. The method should be located in the same class with original method by default. If you want to use method in other classes, you can set the `fallbackClass` with corresponding `Class` (Note the method in other classes must be *static*). The default fallback method signature requirement:
- The return type should match the origin method;
- parameter list should be empty, and an additional `Throwable` parameter can be provided to get the actual exception.
- `blockHandler`: Handler method that handles `BlockException` when blocked. The parameter list of the method should match original method, with the last additional parameter type `BlockException`. The return type should be same as the original method. The `blockHandler` method should be located in the same class with original method by default. If you want to use method in other classes, you can set the `blockHandlerClass` with corresponding `Class` (Note the method in other classes must be *static*).
- `exceptionsToIgnore` (since 1.6.0): List of business exception classes that should not be traced and caught in fallback.
- `exceptionsToTrace` (since 1.5.1): List of business exception classes to trace and record. In most cases, using `exceptionsToIgnore` is better. If both `exceptionsToTrace` and `exceptionsToIgnore` are present, only `exceptionsToIgnore` will be activated.

For example:

```java
@SentinelResource(value = "abc", fallback = "doFallback", blockHandler = "handleException")
@SentinelResource(value = "abc", fallback = "doFallback")
public String doSomething(long i) {
return "Hello " + i;
}

public String doFallback(long i) {
public String doFallback(long i, Throwable t) {
// Return fallback value.
return "Oops, degraded";
return "fallback";
}

public String handleException(long i, BlockException ex) {
// Handle the block exception here.
return null;
public String defaultFallback(Throwable t) {
return "default_fallback";
}
```

Expand Down
Loading