# Sentinel Zuul Adapter
Sentinel Zuul Adapter provides **route level** and **customized API level**
flow control for Zuul API Gateway.
> *Note*: this adapter only support Zuul 1.x.
## How to use
1. Add Maven dependency to your `pom.xml`:
```xml
com.alibaba.csp
sentinel-zuul-adapter
x.y.z
```
2. Register filters
For Spring Cloud Zuul users, we only need to inject the three filters in Spring configuration class like this:
```java
@Configuration
public class ZuulConfig {
@Bean
public ZuulFilter sentinelZuulPreFilter() {
// We can provider the filter order here.
return new SentinelZuulPreFilter(10000);
}
@Bean
public ZuulFilter sentinelZuulPostFilter() {
return new SentinelZuulPostFilter(1000);
}
@Bean
public ZuulFilter sentinelZuulErrorFilter() {
return new SentinelZuulErrorFilter(-1);
}
}
```
For original Zuul users:
```java
// Get filter registry
final FilterRegistry r = FilterRegistry.instance();
// We need to register all three filters.
SentinelZuulPreFilter sentinelPreFilter = new SentinelZuulPreFilter();
r.put("sentinelZuulPreFilter", sentinelPreFilter);
SentinelZuulPostFilter postFilter = new SentinelZuulPostFilter();
r.put("sentinelZuulPostFilter", postFilter);
SentinelZuulErrorFilter errorFilter = new SentinelZuulErrorFilter();
r.put("sentinelZuulErrorFilter", errorFilter);
```
## How it works
As Zuul run as per thread per connection block model, we add filters around route filter to trace Sentinel statistics.
- `SentinelZuulPreFilter`: This pre-filter will regard all proxy ID (`proxy` in `RequestContext`) and all customized API as resources. When a `BlockException` caught, the filter will try to find a fallback to execute.
- `SentinelZuulPostFilter`: When the response has no exception caught, the post filter will complete the entries.
- `SentinelZuulPreFilter`: When an exception is caught, the filter will trace the exception and complete the entries.
The order of filters can be changed via the constructor.
The invocation chain resembles this:
```bash
-EntranceNode: sentinel_gateway_context$$route$$another-route-b(t:0 pq:0.0 bq:0.0 tq:0.0 rt:0.0 prq:0.0 1mp:8 1mb:1 1mt:9)
--another-route-b(t:0 pq:0.0 bq:0.0 tq:0.0 rt:0.0 prq:0.0 1mp:4 1mb:1 1mt:5)
--another_customized_api(t:0 pq:0.0 bq:0.0 tq:0.0 rt:0.0 prq:0.0 1mp:4 1mb:0 1mt:4)
-EntranceNode: sentinel_gateway_context$$route$$my-route-1(t:0 pq:0.0 bq:0.0 tq:0.0 rt:0.0 prq:0.0 1mp:6 1mb:0 1mt:6)
--my-route-1(t:0 pq:0.0 bq:0.0 tq:0.0 rt:0.0 prq:0.0 1mp:2 1mb:0 1mt:2)
--some_customized_api(t:0 pq:0.0 bq:0.0 tq:0.0 rt:0.0 prq:0.0 1mp:2 1mb:0 1mt:2)
```
## Integration with Sentinel Dashboard
1. Start [Sentinel Dashboard](https://github.com/alibaba/Sentinel/wiki/Dashboard).
2. You can configure the rules in Sentinel dashboard or via dynamic rule configuration.
## Fallbacks
You can implement `SentinelFallbackProvider` to define your own fallback provider when Sentinel `BlockException` is thrown.
The default fallback provider is `DefaultBlockFallbackProvider`.
By default fallback route is proxy ID (or customized API name).
Here is an example:
```java
// custom provider
public class MyBlockFallbackProvider implements ZuulBlockFallbackProvider {
private Logger logger = LoggerFactory.getLogger(DefaultBlockFallbackProvider.class);
// you can define root as service level
@Override
public String getRoute() {
return "my-route";
}
@Override
public BlockResponse fallbackResponse(String route, Throwable cause) {
RecordLog.info(String.format("[Sentinel DefaultBlockFallbackProvider] Run fallback route: %s", route));
if (cause instanceof BlockException) {
return new BlockResponse(429, "Sentinel block exception", route);
} else {
return new BlockResponse(500, "System Error", route);
}
}
}
// register fallback
ZuulBlockFallbackManager.registerProvider(new MyBlockFallbackProvider());
```
Default block response:
```json
{
"code":429,
"message":"Sentinel block exception",
"route":"/"
}
```
## Request origin parser
You can register customized request origin parser like this:
```java
public class MyRequestOriginParser implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest request) {
return request.getRemoteAddr();
}
}
```