Skip to content

Commit

Permalink
Add Sentinel annotation and JAX-RS plugins for Quarkus (alibaba#1542)
Browse files Browse the repository at this point in the history
* Add sentinel-quarkus-adapter module, which provides sentinel-annotation-quarkus-adapter and sentinel-jax-rs-quarkus-adapter to adapt sentinel-annotation-cdi-interceptor and sentinel-jax-rs-adapter for Quarkus. It also provides sentinel-native-image-quarkus-adapter to support running Sentinel with Quarkus in native image mode.
  • Loading branch information
seasidesky authored Jun 15, 2020
1 parent ad9cd22 commit 2be25ae
Show file tree
Hide file tree
Showing 22 changed files with 1,446 additions and 0 deletions.
1 change: 1 addition & 0 deletions sentinel-adapter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<module>sentinel-zuul2-adapter</module>
<module>sentinel-okhttp-adapter</module>
<module>sentinel-jax-rs-adapter</module>
<module>sentinel-quarkus-adapter</module>
</modules>

<dependencyManagement>
Expand Down
86 changes: 86 additions & 0 deletions sentinel-adapter/sentinel-quarkus-adapter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# sentinel quarkus adapter

sentinel quarkus adapter provides `sentinel-annotation-quarkus-adapter` and `sentinel-jax-rs-quarkus-adapter` to adapt `sentinel-annotation-cdi-interceptor` and `sentinel-jax-rs-adapter` for quarkus

sentinel quarkus adapter also provides `sentinel-native-image-quarkus-adapter` to support running sentinel with quarkus in native image mode.

To use sentinel-jax-rs-quarkus-adapter, you can simply add the following dependency to your `pom.xml`:

```xml
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-jax-rs-quarkus-adapter</artifactId>
<version>x.y.z</version>
</dependency>
```

To use sentinel-annotation-quarkus-adapter, you can simply add the following dependency to your `pom.xml`:

```xml
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-quarkus-adapter</artifactId>
<version>x.y.z</version>
</dependency>
```

if your quarkus application want to use both `sentinel-annotation-quarkus-adapter` and `sentinel-jax-rs-quarkus-adapter` , then add these two dependency together to your `pom.xml`:

```xml
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-jax-rs-quarkus-adapter</artifactId>
<version>x.y.z</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-quarkus-adapter</artifactId>
<version>x.y.z</version>
</dependency>
```

when quarkus application started, you can see the enabled feature like:

```
INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, resteasy, sentinel-annotation, sentinel-jax-rs]
```

## for quarkus native image

if you want to make sentinel with quarkus running in native image mode, you should add the following dependency to your `pom.xml`:

```xml
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-native-image-quarkus-adapter</artifactId>
<version>x.y.z</version>
</dependency>
```

and then add `--allow-incomplete-classpath` to `quarkus.native.additional-build-args`.

if you use `sentinel-jax-rs-quarkus-adapter` you should set `quarkus.native.auto-service-loader-registration` to true.

you can refer to `sentinel-demo-quarkus`'s `pom.xml` for more details.

when quarkus application started, you can see the enabled feature like:

```
INFO [io.quarkus] (main) Installed features: [cdi, resteasy, sentinel-annotation, sentinel-jax-rs, sentinel-native-image]
```

### notes for limitations

`sentinel-native-image-quarkus-adapter` currently rely on `sentinel-logging-slf4j` to make sentinel run in native image mode easily, because `quarkus-core` provides `Target_org_slf4j_LoggerFactory` to substitue `getLogger` method.

currently `sentinel-transport-simple-http` can work in native image mode, while `sentinel-transport-netty-http` cannot work in native image mode without extra config or substitutions.

## references for build native image or AOT

- [Quarkus - Tips for writing native applications](https://quarkus.io/guides/writing-native-applications-tips)

- [Quarkus - Class Loading Reference](https://quarkus.io/guides/class-loading-reference)

- [substratevm LIMITATIONS](https://github.com/oracle/graal/blob/master/substratevm/LIMITATIONS.md)

- [Accessing resources in Substrate VM images](https://github.com/oracle/graal/blob/master/substratevm/RESOURCES.md)
55 changes: 55 additions & 0 deletions sentinel-adapter/sentinel-quarkus-adapter/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-adapter</artifactId>
<version>1.8.0-SNAPSHOT</version>
</parent>

<artifactId>sentinel-quarkus-adapter-parent</artifactId>
<packaging>pom</packaging>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.parameters>true</maven.compiler.parameters>
<quarkus.version>1.4.1.Final</quarkus.version>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
</properties>

<modules>
<module>sentinel-annotation-quarkus-adapter-deployment</module>
<module>sentinel-annotation-quarkus-adapter-runtime</module>
<module>sentinel-jax-rs-quarkus-adapter-deployment</module>
<module>sentinel-jax-rs-quarkus-adapter-runtime</module>
<module>sentinel-native-image-quarkus-adapter-deployment</module>
<module>sentinel-native-image-quarkus-adapter-runtime</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-bom-deployment</artifactId>
<version>${quarkus.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-quarkus-adapter-parent</artifactId>
<version>1.8.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

<artifactId>sentinel-annotation-quarkus-adapter-deployment</artifactId>
<name>sentinel-annotation-quarkus-adapter-deployment</name>

<properties>
<java.source.version>1.8</java.source.version>
<java.target.version>1.8</java.target.version>
</properties>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-core-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc-deployment</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-quarkus-adapter</artifactId>
<version>${project.version}</version>
</dependency>

<!-- Test dependencies -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc-deployment</artifactId>
</dependency>

</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${quarkus.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.annotation.quarkus.adapter.deployment;

import com.alibaba.csp.sentinel.annotation.cdi.interceptor.SentinelResourceInterceptor;
import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.FeatureBuildItem;

import java.util.Arrays;
import java.util.List;

/**
* @author sea
*/
class SentinelAnnotationQuarkusAdapterProcessor {

private static final String FEATURE_ANNOTATION = "sentinel-annotation";

@BuildStep
void feature(BuildProducer<FeatureBuildItem> featureProducer) {
featureProducer.produce(new FeatureBuildItem(FEATURE_ANNOTATION));
}

@BuildStep
List<AdditionalBeanBuildItem> additionalBeans() {
return Arrays.asList(
new AdditionalBeanBuildItem(SentinelResourceInterceptor.class)
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.annotation.quarkus.adapter.deployment;
import com.alibaba.csp.sentinel.annotation.cdi.interceptor.SentinelResourceBinding;
import com.alibaba.csp.sentinel.slots.block.BlockException;

import javax.enterprise.context.ApplicationScoped;
import java.util.concurrent.ThreadLocalRandom;

/**
* @author Eric Zhao
* @author sea
*/
@ApplicationScoped
public class FooService {

@SentinelResourceBinding(value = "apiFoo", blockHandler = "fooBlockHandler",
exceptionsToTrace = {IllegalArgumentException.class})
public String foo(int i) throws Exception {
if (i == 5758) {
throw new IllegalAccessException();
}
if (i == 5763) {
throw new IllegalArgumentException();
}
return "Hello for " + i;
}

@SentinelResourceBinding(value = "apiFooWithFallback", blockHandler = "fooBlockHandler", fallback = "fooFallbackFunc",
exceptionsToTrace = {IllegalArgumentException.class})
public String fooWithFallback(int i) throws Exception {
if (i == 5758) {
throw new IllegalAccessException();
}
if (i == 5763) {
throw new IllegalArgumentException();
}
return "Hello for " + i;
}

@SentinelResourceBinding(value = "apiAnotherFooWithDefaultFallback", defaultFallback = "globalDefaultFallback",
fallbackClass = {FooUtil.class})
public String anotherFoo(int i) {
if (i == 5758) {
throw new IllegalArgumentException("oops");
}
return "Hello for " + i;
}

@SentinelResourceBinding(blockHandler = "globalBlockHandler", blockHandlerClass = FooUtil.class)
public int random() {
return ThreadLocalRandom.current().nextInt(0, 30000);
}

@SentinelResourceBinding(value = "apiBaz", blockHandler = "bazBlockHandler",
exceptionsToIgnore = {IllegalMonitorStateException.class})
public String baz(String name) {
if (name.equals("fail")) {
throw new IllegalMonitorStateException("boom!");
}
return "cheers, " + name;
}

public String fooBlockHandler(int i, BlockException ex) {
return "Oops, " + i;
}

public String fooFallbackFunc(int i) {
return "eee...";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 1999-2020 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.annotation.quarkus.adapter.deployment;

import com.alibaba.csp.sentinel.slots.block.BlockException;

/**
* @author Eric Zhao
*/
public class FooUtil {

public static final int BLOCK_FLAG = 88888;
public static final String FALLBACK_DEFAULT_RESULT = "fallback";

public static int globalBlockHandler(BlockException ex) {
System.out.println("Oops: " + ex.getClass().getSimpleName());
return BLOCK_FLAG;
}

public static String globalDefaultFallback(Throwable t) {
System.out.println("Fallback caught: " + t.getClass().getSimpleName());
return FALLBACK_DEFAULT_RESULT;
}
}
Loading

0 comments on commit 2be25ae

Please sign in to comment.