Compare commits

..

10 Commits
3.2 ... 3.0

3718 changed files with 56282 additions and 160547 deletions

View File

@ -1,117 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
#
# Please add new modules to the end of the list.
dubbo
dubbo-auth
dubbo-apache-release
dubbo-bom
dubbo-build-tools
dubbo-cluster
dubbo-common
dubbo-compatible
dubbo-compiler
dubbo-config
dubbo-config-api
dubbo-config-spring
dubbo-configcenter
dubbo-configcenter-apollo
dubbo-configcenter-nacos
dubbo-configcenter-zookeeper
dubbo-container
dubbo-container-api
dubbo-container-spring
dubbo-core-spi
dubbo-dependencies
dubbo-dependencies-all
dubbo-dependencies-bom
dubbo-dependencies-zookeeper
dubbo-dependencies-zookeeper-curator5
dubbo-distribution
dubbo-filter
dubbo-filter-cache
dubbo-filter-validation
dubbo-kubernetes
dubbo-maven-plugin
dubbo-metadata
dubbo-metadata-api
dubbo-metadata-definition-protobuf
dubbo-metadata-processor
dubbo-metadata-report-nacos
dubbo-metadata-report-redis
dubbo-metadata-report-zookeeper
dubbo-metrics
dubbo-metrics-api
dubbo-metrics-default
dubbo-metrics-metadata
dubbo-metrics-prometheus
dubbo-metrics-registry
dubbo-metrics-config-center
dubbo-monitor
dubbo-monitor-api
dubbo-monitor-default
dubbo-native
dubbo-native-plugin
dubbo-parent
dubbo-plugin
dubbo-qos
dubbo-qos-api
dubbo-reactive
dubbo-registry
dubbo-registry-api
dubbo-registry-multicast
dubbo-registry-multiple
dubbo-registry-nacos
dubbo-registry-zookeeper
dubbo-remoting
dubbo-remoting-api
dubbo-remoting-http
dubbo-remoting-netty
dubbo-remoting-netty4
dubbo-remoting-zookeeper
dubbo-remoting-zookeeper-curator5
dubbo-rpc
dubbo-rpc-api
dubbo-rpc-dubbo
dubbo-rpc-injvm
dubbo-rpc-rest
dubbo-rpc-triple
dubbo-security
dubbo-serialization
dubbo-serialization-api
dubbo-serialization-fastjson2
dubbo-serialization-hessian2
dubbo-serialization-jdk
dubbo-spring-boot
dubbo-spring-boot-actuator
dubbo-spring-boot-actuator-compatible
dubbo-spring-boot-autoconfigure
dubbo-spring-boot-autoconfigure-compatible
dubbo-spring-boot-compatible
dubbo-spring-boot-observability-starters
dubbo-spring-boot-observability-autoconfigure
dubbo-spring-boot-tracing-brave-zipkin-starter
dubbo-spring-boot-tracing-otel-zipkin-starter
dubbo-spring-boot-tracing-otel-otlp-starter
dubbo-spring-boot-observability-starter
dubbo-spring-boot-starter
dubbo-spring-boot-starters
dubbo-nacos-spring-boot-starter
dubbo-zookeeper-spring-boot-starter
dubbo-zookeeper-curator5-spring-boot-starter
dubbo-spring-security
dubbo-xds

View File

@ -25,7 +25,6 @@ notifications:
github: github:
homepage: https://dubbo.apache.org/ homepage: https://dubbo.apache.org/
description: "The java implementation of Apache Dubbo. An RPC and microservice framework."
features: features:
# Enable wiki for documentation # Enable wiki for documentation
wiki: true wiki: true
@ -43,17 +42,3 @@ github:
3.1: 3.1:
# only disable force push # only disable force push
foo: bar foo: bar
labels:
- java
- rpc
- microservices
- framework
- restful
- distributed-systems
- dubbo
- service-mesh
- http
- grpc
- web
collaborators:
- oxsean

11
.codecov.yml Normal file
View File

@ -0,0 +1,11 @@
coverage:
status:
# pull-requests only
patch:
default:
threshold: 0.1%
ignore:
- "dubbo-demo/.*"
- "dubbo-common/src/main/java/org/apache/dubbo/common/json/*.java" # internal JSON impl is deprecate, ignore test coverage for them
- "dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/AnnotationBean.java" # Deprecated
- "dubbo-rpc/dubbo-rpc-thrift/.*"

View File

@ -19,55 +19,13 @@
# top-most EditorConfig file # top-most EditorConfig file
root = true root = true
# Unix-style newlines with a newline ending every file
[*] [*]
charset = utf-8 charset = utf-8
end_of_line = lf end_of_line = lf
indent_size = 4
indent_style = space
tab_width = 4
max_line_length = 120
insert_final_newline = true insert_final_newline = true
trim_trailing_whitespace = true
[*.java] # 4 space indentation
ij_java_continuation_indent_size = 8 [*.{java,xml}]
ij_java_keep_control_statement_in_one_line = false indent_style = space
ij_java_for_brace_force = always indent_size = 4
ij_java_if_brace_force = always
ij_java_keep_first_column_comment = false
ij_java_keep_line_breaks = false
ij_java_keep_simple_blocks_in_one_line = true
ij_java_keep_simple_classes_in_one_line = true
ij_java_keep_simple_lambdas_in_one_line = true
ij_java_keep_simple_methods_in_one_line = true
ij_java_keep_blank_lines_in_code = 1
ij_java_keep_blank_lines_in_declarations = 1
ij_java_class_count_to_use_import_on_demand = 999
ij_java_names_count_to_use_import_on_demand = 999
ij_java_imports_layout = org.apache.dubbo.**, |, javax.**, |, java.**, |, *, |, $*
ij_java_insert_inner_class_imports = true
ij_java_space_before_array_initializer_left_brace = true
ij_java_method_parameters_new_line_after_left_paren = true
ij_java_wrap_comments = true
ij_java_wrap_long_lines = true
ij_java_enum_constants_wrap = split_into_lines
ij_java_method_call_chain_wrap = split_into_lines
ij_java_method_parameters_wrap = on_every_item
ij_java_extends_list_wrap = on_every_item
ij_java_extends_keyword_wrap = normal
ij_java_binary_operation_wrap = normal
ij_java_binary_operation_sign_on_next_line = true
[*.json]
tab_width = 2
[*.{yml,yaml}]
indent_size = 2
[*.xml]
ij_xml_attribute_wrap = off
ij_xml_text_wrap = off
ij_xml_keep_blank_lines = 1
[pom.xml]
indent_size = 2

View File

@ -1,88 +0,0 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
#
title: "[General][Java SDK (Component)] xxx"
body:
- type: markdown
attributes:
value: |
<img src="https://dubbo.apache.org/imgs/nav_logo2.png" alt="Dubbo logo" height="90px" align="right" />
Thank you for finding the time to share your idea! We really appreciate the community efforts to improve Dubbo.
If you need to report a security issue, please visit [our security policy](https://github.com/apache/dubbo/security/policy).
**Dubbo is open for world wide collaboration, please make sure that all the content you provide is in English.**
Remember that non-English idea is quite not friendly for everyone, and might unable to get the response!
- type: checkboxes
attributes:
label: Pre-check
options:
- label: >
I am sure that all the content I provide is in English.
required: true
- type: dropdown
attributes:
label: Apache Dubbo Component
description: |
What Apache Dubbo component are you using? Apache Dubbo has many subprojects, please make sure
to choose the component that you want to ask questions about.
multiple: false
options:
- "Java SDK (apache/dubbo)"
- "Java Samples (apache/dubbo-samples)"
- "Java Integration Cases (apache/dubbo-integration-cases)"
- "Java SPI Extensions (apache/dubbo-spi-extensions)"
- "Java Benchmark (apache/dubbo-benchmark)"
- "Go SDK (apache/dubbo-go)"
- "Go Samples (apache/dubbo-go-samples)"
- "Rust SDK (apache/dubbo-rust)"
- "Node.js SDK (apache/dubbo-js)"
- "Python SDK (apache/dubbo-python)"
- "Kubernetes Integration (apache/dubbo-kubernetes)"
- "Pixiu Gateway (apache/dubbo-go-pixiu)"
- "Pixiu Gateway Samples (apache/dubbo-go-pixiu-samples)"
- "Admin (apache/dubbo-admin)"
- "Website (apache/dubbo-website)"
- "Awesome (apache/dubbo-awesome)"
- "Initializer (apache/dubbo-intializer)"
- "Others (apache/dubbo-xxx)"
validations:
required: true
- type: textarea
attributes:
label: Details
description: Anything you want to ask?
validations:
required: true
- type: checkboxes
attributes:
label: Code of Conduct
description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.
options:
- label: >
I agree to follow this project's
[Code of Conduct](https://www.apache.org/foundation/policies/conduct)
required: true
- type: markdown
attributes:
value: "Thanks for completing our form!"

View File

@ -1,88 +0,0 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
#
title: "[Q/A][Java SDK (Component)] xxx"
body:
- type: markdown
attributes:
value: |
<img src="https://dubbo.apache.org/imgs/nav_logo2.png" alt="Dubbo logo" height="90px" align="right" />
Thank you for finding the time to report the question! We really appreciate the community efforts to improve Dubbo.
If you need to report a security issue, please visit [our security policy](https://github.com/apache/dubbo/security/policy).
**Dubbo is open for world wide collaboration, please make sure that all the content you provide is in English.**
Remember that non-English question is quite not friendly for everyone, and might unable to get the response!
- type: checkboxes
attributes:
label: Pre-check
options:
- label: >
I am sure that all the content I provide is in English.
required: true
- type: dropdown
attributes:
label: Apache Dubbo Component
description: |
What Apache Dubbo component are you using? Apache Dubbo has many subprojects, please make sure
to choose the component that you want to ask questions about.
multiple: false
options:
- "Java SDK (apache/dubbo)"
- "Java Samples (apache/dubbo-samples)"
- "Java Integration Cases (apache/dubbo-integration-cases)"
- "Java SPI Extensions (apache/dubbo-spi-extensions)"
- "Java Benchmark (apache/dubbo-benchmark)"
- "Go SDK (apache/dubbo-go)"
- "Go Samples (apache/dubbo-go-samples)"
- "Rust SDK (apache/dubbo-rust)"
- "Node.js SDK (apache/dubbo-js)"
- "Python SDK (apache/dubbo-python)"
- "Kubernetes Integration (apache/dubbo-kubernetes)"
- "Pixiu Gateway (apache/dubbo-go-pixiu)"
- "Pixiu Gateway Samples (apache/dubbo-go-pixiu-samples)"
- "Admin (apache/dubbo-admin)"
- "Website (apache/dubbo-website)"
- "Awesome (apache/dubbo-awesome)"
- "Initializer (apache/dubbo-intializer)"
- "Others (apache/dubbo-xxx)"
validations:
required: true
- type: textarea
attributes:
label: Details
description: Anything you want to know?
validations:
required: true
- type: checkboxes
attributes:
label: Code of Conduct
description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.
options:
- label: >
I agree to follow this project's
[Code of Conduct](https://www.apache.org/foundation/policies/conduct)
required: true
- type: markdown
attributes:
value: "Thanks for completing our form!"

View File

@ -1,142 +0,0 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
#
name: Bug Report
description: File a bug report
title: "[Bug] "
labels: ["type/need-triage", "component/need-triage"]
projects: ["apache/337"]
body:
- type: markdown
attributes:
value: |
<img src="https://dubbo.apache.org/imgs/nav_logo2.png" alt="Dubbo logo" height="90px" align="right" />
Thank you for finding the time to report the problem! We really appreciate the community efforts to improve Dubbo.
Please make sure what you are reporting is indeed a bug with reproducible steps, if you want to ask questions
or share ideas, please [subscribe to our mailing list](mailto:dev-subscribe@dubbo.apache.org) and sent
emails to [our mailing list](mailto:dev@dubbo.apache.org), you can also head to our
[Discussion](https://github.com/apache/dubbo/discussions) tab.
If you need to report a security issue, please visit [our security policy](https://github.com/apache/dubbo/security/policy).
**Dubbo is open for world wide collaboration, please make sure that all the content you provide is in English.**
Remember that non-English issues is quite not friendly for everyone, and might unable to get the response!
- type: checkboxes
attributes:
label: Pre-check
options:
- label: >
I am sure that all the content I provide is in English.
required: true
- type: checkboxes
attributes:
label: Search before asking
description: >
Please make sure to search in the [issues](https://github.com/apache/dubbo/issues?q=is%3Aissue) first to see
whether the same issue was reported already.
options:
- label: >
I had searched in the [issues](https://github.com/apache/dubbo/issues?q=is%3Aissue) and found no similar
issues.
required: true
- type: dropdown
attributes:
label: Apache Dubbo Component
description: |
What Apache Dubbo component are you using? Apache Dubbo has many subprojects, please make sure
to choose the component that you want to ask questions about.
multiple: false
options:
- "Java SDK (apache/dubbo)"
- "Java Samples (apache/dubbo-samples)"
- "Java Integration Cases (apache/dubbo-integration-cases)"
- "Java SPI Extensions (apache/dubbo-spi-extensions)"
- "Java Benchmark (apache/dubbo-benchmark)"
validations:
required: true
- type: textarea
attributes:
label: Dubbo Version
description: "Which Dubbo version, JDK version and operating system did you use?"
placeholder: "Example: Dubbo Java 3.2.12, OpenJDK 1.8, Ubuntu 20.04"
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce this issue
description: >
Describe how to reproduce this issue.If you are not able to provide a reproducible case,
please open a [Discussion](https://github.com/apache/dubbo/discussions) instead.
placeholder: >
Please provide the context in which the problem occurred and explain what happened.
A [GitHub address] would be helpful for maintainers to reproduce the problem.
validations:
required: true
- type: textarea
attributes:
label: What you expected to happen
description: What do you think went wrong?
placeholder: >
Please explain why you think the behaviour is erroneous. It is extremely helpful if you copy and paste
the fragment of logs showing the exact error messages or wrong behaviour and screenshots for
UI problems. You can include files by dragging and dropping them here.
**NOTE**: please copy and paste texts instead of taking screenshots of them for easy future search.
validations:
required: true
- type: textarea
attributes:
label: Anything else
description: Anything else we need to know?
placeholder: >
How often does this problem occur? (Once? Every time? Only when certain conditions are met?)
Any relevant logs to include? Put them here inside fenced
``` ``` blocks or inside a collapsable details tag if it's too long:
<details><summary>x.log</summary> lots of stuff </details>
- type: checkboxes
attributes:
label: Are you willing to submit a pull request to fix on your own?
description: >
This is absolutely not required, but we are happy to guide you in the contribution process
especially if you already have a good understanding of how to implement the fix.
Dubbo is a totally community-driven project and we love to bring new contributors in.
options:
- label: Yes I am willing to submit a pull request on my own!
- type: checkboxes
attributes:
label: Code of Conduct
description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.
options:
- label: >
I agree to follow this project's
[Code of Conduct](https://www.apache.org/foundation/policies/conduct)
required: true
- type: markdown
attributes:
value: "Thanks for completing our form!"

View File

@ -1,106 +0,0 @@
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
#
name: Feature Request
description: Create a Feature Request for Dubbo
title: "[Feature] "
labels: ["type/need-triage", "component/need-triage"]
projects: ["apache/337"]
body:
- type: markdown
attributes:
value: |
<img src="https://dubbo.apache.org/imgs/nav_logo2.png" alt="Dubbo logo" height="90px" align="right" />
Thank you for finding the time to propose new feature!
We really appreciate the community efforts to improve Dubbo.
**Dubbo is open for world wide collaboration, please make sure that all the content you provide is in English.**
Remember that non-English issues is quite not friendly for everyone, and might unable to get the response!
- type: checkboxes
attributes:
label: Pre-check
options:
- label: >
I am sure that all the content I provide is in English.
required: true
- type: checkboxes
attributes:
label: Search before asking
description: >
Please make sure to search in the [issues](https://github.com/apache/dubbo/issues?q=is%3Aissue) first to see
whether the same feature was requested already.
options:
- label: >
I had searched in the [issues](https://github.com/apache/dubbo/issues?q=is%3Aissue) and found no similar
feature requirement.
required: true
- type: dropdown
attributes:
label: Apache Dubbo Component
description: |
What Apache Dubbo component are you using? Apache Dubbo has many subprojects, please make sure
to choose the component that you want to ask questions about.
multiple: false
options:
- "Java SDK (apache/dubbo)"
- "Java Samples (apache/dubbo-samples)"
- "Java Integration Cases (apache/dubbo-integration-cases)"
- "Java SPI Extensions (apache/dubbo-spi-extensions)"
- "Java Benchmark (apache/dubbo-benchmark)"
validations:
required: true
- type: textarea
attributes:
label: Descriptions
description: A short description of your feature
validations:
required: true
- type: textarea
attributes:
label: Related issues
description: Is there currently another issue associated with this?
- type: checkboxes
attributes:
label: Are you willing to submit a pull request to fix on your own?
description: >
This is absolutely not required, but we are happy to guide you in the contribution process
especially if you already have a good understanding of how to implement the feature.
Dubbo is a totally community-driven project and we love to bring new contributors in.
options:
- label: Yes I am willing to submit a pull request on my own!
- type: checkboxes
attributes:
label: Code of Conduct
description: The Code of Conduct helps create a safe space for everyone. We require that everyone agrees to it.
options:
- label: >
I agree to follow this project's
[Code of Conduct](https://www.apache.org/foundation/policies/conduct)
required: true
- type: markdown
attributes:
value: "Thanks for completing our form!"

39
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,39 @@
---
name: Bug Report
about: Report a bug in Dubbo
title: ''
labels: type/bug
assignees: ''
---
<!-- If you need to report a security issue please visit https://github.com/apache/dubbo/security/policy -->
- [ ] I have searched the [issues](https://github.com/apache/dubbo/issues) of this repository and believe that this is not a duplicate.
### Environment
* Dubbo version: xxx
* Operating System version: xxx
* Java version: xxx
### Steps to reproduce this issue
1. xxx
2. xxx
3. xxx
Pls. provide [GitHub address] to reproduce this issue.
### Expected Behavior
<!-- What do you expect from the above steps-->
### Actual Behavior
<!-- What actually happens? -->
If there is an exception, please attach the exception trace:
```
Just put your stack trace here!
```

View File

@ -1,22 +1,8 @@
# blank_issues_enabled: true
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
#
blank_issues_enabled: false
contact_links: contact_links:
- name: Question & FAQ & Proposal - name: Dubbo Community Repo
url: https://github.com/apache/dubbo/discussions/ url: https://github.com/apache/dubbo-website
about: Ask a question, request support or submit a proposal for Apache Dubbo. about: Please see our community docs here.
- name: Report a security issue
url: https://github.com/apache/dubbo/security/policy
about: Please report security vulnerabilities using these instructions.

11
.github/ISSUE_TEMPLATE/discussion.md vendored Normal file
View File

@ -0,0 +1,11 @@
---
name: Discussion
about: Start a discussion for Dubbo
title: ''
labels: type/discussion
assignees: ''
---
<!-- If you need to report a security issue please visit https://github.com/apache/dubbo/security/policy -->
<!-- For all design discussions please continue. -->

View File

@ -0,0 +1,16 @@
---
name: Feature Request
about: Create a Feature Request for Dubbo
title: ''
labels: type/feature
assignees: ''
---
<!-- If you need to report a security issue please visit https://github.com/apache/dubbo/security/policy -->
- [ ] I have searched the [issues](https://github.com/apache/dubbo/issues) of this repository and believe that this is not a duplicate.
- [ ] I have searched the [release notes](https://github.com/apache/dubbo/releases) of this repository and believe that this is not a duplicate.
## Describe the feature
<!-- Please also discuss possible business value -->

15
.github/ISSUE_TEMPLATE/proposal.md vendored Normal file
View File

@ -0,0 +1,15 @@
---
name: Proposal
about: Create a technical proposal for Dubbo
title: ''
labels: type/proposal
assignees: ''
---
<!-- If you need to report a security issue please visit https://github.com/apache/dubbo/security/policy -->
- [ ] I have searched the [issues](https://github.com/apache/dubbo/issues) of this repository and believe that this is not a duplicate.
## Describe the proposal
<!-- Please use this for a concrete design proposal for functionality. -->
<!-- If you just want to request a new feature and discuss the possible business value, create a Feature Request. -->

13
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View File

@ -0,0 +1,13 @@
---
name: Question
about: Ask a question about Dubbo
title: ''
labels: type/question
assignees: ''
---
<!-- If you need to report a security issue please visit https://github.com/apache/dubbo/security/policy -->
- [ ] I have searched the [issues](https://github.com/apache/dubbo/issues) of this repository and believe that this is not a duplicate.
## Ask your question here

View File

@ -1,15 +0,0 @@
version: 2
updates:
- package-ecosystem: "maven"
directory: "/"
open-pull-requests-limit: 20
# Ignore major version updates
ignore:
- dependency-name: "*"
update-types: ["version-update:semver-major"]
schedule:
interval: "weekly"
day: "monday"
time: "03:00"
timezone: "US/Eastern"

244
.github/workflows/build-and-test-3.yml vendored Normal file
View File

@ -0,0 +1,244 @@
name: Build and Test For Dubbo 3
on: [push, pull_request, workflow_dispatch]
env:
FORK_COUNT: 2
FAIL_FAST: 0
SHOW_ERROR_DETAIL: 1
#multi-version size limit
VERSIONS_LIMIT: 4
CANDIDATE_VERSIONS: '
spring.version:4.3.30.RELEASE;
spring-boot.version:1.5.22.RELEASE;
spring-boot.version:2.4.1;
'
jobs:
build-source:
runs-on: ubuntu-18.04
outputs:
version: ${{ steps.dubbo-version.outputs.version }}
steps:
- uses: actions/checkout@v2
with:
path: dubbo
- uses: actions/setup-java@v1
with:
java-version: 8
- uses: actions/cache@v2
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- name: "Dubbo cache"
uses: actions/cache@v2
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}
- name: "Build Dubbo with Maven"
run: |
cd ./dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean source:jar install -Pjacoco,rat,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Pack rat file if failure"
if: failure()
run: 7z a ${{ github.workspace }}/rat.zip *rat.txt -r
- name: "Upload rat file if failure"
if: failure()
uses: actions/upload-artifact@v2
with:
name: "rat-file"
path: ${{ github.workspace }}/rat.zip
- name: "Pack checkstyle file if failure"
if: failure()
run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r
- name: "Upload checkstyle file if failure"
if: failure()
uses: actions/upload-artifact@v2
with:
name: "checkstyle-file"
path: ${{ github.workspace }}/checkstyle.zip
- name: "Calculate Dubbo Version"
id: dubbo-version
run: |
REVISION=`awk '/<revision>[^<]+<\/revision>/{gsub(/<revision>|<\/revision>/,"",$1);print $1;exit;}' ./dubbo/pom.xml`
echo "::set-output name=version::$REVISION"
echo "dubbo version: $REVISION"
unit-test-prepare:
name: " Preparation for Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }})"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-18.04, windows-2019 ]
jdk: [ 8, 11, 17 ]
env:
DISABLE_FILE_SYSTEM_TEST: true
ZOOKEEPER_VERSION: 3.6.3
steps:
- uses: actions/cache@v2
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
- name: "Set up msys2 if necessary"
if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
uses: msys2/setup-msys2@v2
with:
release: false # support cache, see https://github.com/msys2/setup-msys2#context
- name: "Download zookeeper binary archive in Linux OS"
if: ${{ startsWith( matrix.os, 'ubuntu') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
run: |
mkdir -p ${{ github.workspace }}/.tmp/zookeeper
wget -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.stu.edu.tw/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
echo "list the downloaded zookeeper binary archive"
ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
- name: "Download zookeeper binary archive in Windows OS"
if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
shell: msys2 {0}
run: |
mkdir -p ${{ github.workspace }}/.tmp/zookeeper
wget -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.stu.edu.tw/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
echo "list the downloaded zookeeper binary archive"
ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
unit-test:
needs: [build-source, unit-test-prepare]
name: "Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }})"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-18.04, windows-2019 ]
jdk: [ 8, 11, 17 ]
env:
DISABLE_FILE_SYSTEM_TEST: true
steps:
- uses: actions/checkout@v2
- name: "Set up JDK ${{ matrix.jdk }}"
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.jdk }}
- uses: actions/cache@v2
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: "Test with Maven with Integration Tests"
timeout-minutes: 70
if: ${{ startsWith( matrix.os, 'ubuntu') }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Test with Maven without Integration Tests"
timeout-minutes: 90
if: ${{ startsWith( matrix.os, 'windows') }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true" -D"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper"
- name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v1
integration-test-prepare:
runs-on: ubuntu-18.04
env:
JOB_COUNT: 3
steps:
- uses: actions/checkout@v2
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Prepare test list"
run: |
bash ./test/scripts/prepare-test.sh
- name: "Upload test list"
uses: actions/upload-artifact@v2
with:
name: test-list
path: test/jobs
integration-test-job:
needs: [build-source, integration-test-prepare]
name: "Integration Test on ubuntu-18.04 (JobId: ${{matrix.job_id}})"
runs-on: ubuntu-18.04
timeout-minutes: 30
env:
JAVA_VER: 8
TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt
strategy:
fail-fast: false
matrix:
job_id: [1, 2, 3]
steps:
- uses: actions/checkout@v2
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Cache local Maven repository"
uses: actions/cache@v2
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: "Restore Dubbo cache"
uses: actions/cache@v2
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}
- name: "Download test list"
uses: actions/download-artifact@v2
with:
name: test-list
path: test/jobs/
- name: "Set up JDK 8"
uses: actions/setup-java@v1
with:
java-version: 8
- name: "Init Candidate Versions"
run: |
DUBBO_VERSION="${{needs.build-source.outputs.version}}"
CANDIDATE_VERSIONS="dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION"
echo "CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS" >> $GITHUB_ENV
- name: "Build test image"
run: |
cd test && bash ./build-test-image.sh
- name: "Run tests"
run: cd test && bash ./run-tests.sh
- name: "Upload test result"
if: always()
uses: actions/upload-artifact@v2
with:
name: test-result
path: test/jobs/*-result*
integration-test-result:
needs: [integration-test-job]
if: always()
runs-on: ubuntu-18.04
env:
JAVA_VER: 8
steps:
- uses: actions/checkout@v2
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Download test result"
uses: actions/download-artifact@v2
with:
name: test-result
path: test/jobs/
- name: "Merge test result"
run: ./test/scripts/merge-test-results.sh

View File

@ -1,604 +0,0 @@
name: Build and Test For PR
on: [push, pull_request, workflow_dispatch]
permissions:
contents: read
env:
FORK_COUNT: 2
FAIL_FAST: 0
SHOW_ERROR_DETAIL: 1
#multi-version size limit
VERSIONS_LIMIT: 4
JACOCO_ENABLE: true
CANDIDATE_VERSIONS: '
spring.version:5.3.24;
spring-boot.version:2.7.6;
'
jobs:
check-format:
name: Check if code needs formatting
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Maven
uses: actions/setup-java@v4
with:
java-version: 21
distribution: zulu
- name: Check if code aligns with code style
id: check
run: mvn --log-file mvn.log spotless:check
continue-on-error: true
- name: Upload checkstyle result
uses: actions/upload-artifact@v4
with:
name: checkstyle-result
path: mvn.log
- name: Generate Summary for successful run
if: ${{ steps.check.outcome == 'success' }}
run: |
echo ":ballot_box_with_check: Kudos! No formatting issues found!" >> $GITHUB_STEP_SUMMARY
- name: Generate Summary for failed run
if: ${{ steps.check.outcome == 'failure' }}
run: |
echo "## :negative_squared_cross_mark: Formatting issues found!" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
cat mvn.log | grep "ERROR" | sed 's/Check if code needs formatting Check if code aligns with code style [0-9A-Z:.-]\+//' | sed 's/\[ERROR] //' | head -n -11 >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "Please run \`mvn spotless:apply\` to fix the formatting issues." >> $GITHUB_STEP_SUMMARY
- name: Fail if code needs formatting
if: ${{ steps.check.outcome == 'failure' }}
uses: actions/github-script@v7.0.1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
core.setFailed("Formatting issues found!")
license:
name: "Check License"
needs: check-format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Check License
uses: apache/skywalking-eyes@e1a02359b239bd28de3f6d35fdc870250fa513d5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: "Set up JDK 21"
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 21
- name: "Compile Dubbo (Linux)"
run: |
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true
- name: Check Dependencies' License
uses: apache/skywalking-eyes/dependency@e1a02359b239bd28de3f6d35fdc870250fa513d5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
config: .licenserc.yaml
mode: check
build-source:
name: "Build Dubbo"
needs: check-format
runs-on: ubuntu-latest
outputs:
version: ${{ steps.dubbo-version.outputs.version }}
steps:
- uses: actions/checkout@v3
with:
path: dubbo
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 8
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
- name: "Build Dubbo with Maven"
run: |
cd ./dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean source:jar install -Pjacoco,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Pack class result"
run: |
shopt -s globstar
zip ${{ github.workspace }}/class.zip **/target/classes/* -r
- name: "Upload class result"
uses: actions/upload-artifact@v3
with:
name: "class-file"
path: ${{ github.workspace }}/class.zip
- name: "Pack checkstyle file if failure"
if: failure()
run: zip ${{ github.workspace }}/checkstyle.zip *checkstyle* -r
- name: "Upload checkstyle file if failure"
if: failure()
uses: actions/upload-artifact@v3
with:
name: "checkstyle-file"
path: ${{ github.workspace }}/checkstyle.zip
- name: "Calculate Dubbo Version"
id: dubbo-version
run: |
REVISION=`awk '/<revision>[^<]+<\/revision>/{gsub(/<revision>|<\/revision>/,"",$1);print $1;exit;}' ./dubbo/pom.xml`
echo "version=$REVISION" >> $GITHUB_OUTPUT
echo "dubbo version: $REVISION"
unit-test-prepare:
name: "Preparation for Unit Test"
needs: check-format
runs-on: ubuntu-latest
strategy:
fail-fast: false
env:
ZOOKEEPER_VERSION: 3.6.3
steps:
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
- name: "Set up msys2 if necessary"
if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
uses: msys2/setup-msys2@v2
with:
release: false # support cache, see https://github.com/msys2/setup-msys2#context
- name: "Download zookeeper binary archive in Linux OS"
run: |
mkdir -p ${{ github.workspace }}/.tmp/zookeeper
wget -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.stu.edu.tw/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
echo "list the downloaded zookeeper binary archive"
ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
- uses: actions/cache@v3
name: "Cache secret key"
id: "cache-secret-cert"
with:
path: ${{ github.workspace }}/.tmp/rsa
key: secret-rsa-${{ runner.os }}-${{ github.run_id }}
- name: "Create Secret"
run: |
mkdir -p ${{ github.workspace }}/.tmp/rsa
cd ${{ github.workspace }}/.tmp/rsa
openssl genrsa -out rsa_private.pem 1024
openssl rsa -in rsa_private.pem -pubout -out rsa_public.pem
echo "Current workflow run id: ${{ github.run_id }}"
echo "Start Print Rsa Public Key ---"
cat rsa_public.pem
echo "--- End Print Rsa Public Key"
unit-test:
needs: [check-format, build-source, unit-test-prepare]
name: "Unit Test On ubuntu-latest"
runs-on: ubuntu-latest
strategy:
fail-fast: false
env:
DISABLE_FILE_SYSTEM_TEST: true
CURRENT_ROLE: ${{ matrix.case-role }}
DUBBO_DEFAULT_SERIALIZATION: fastjson2
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: "Set up JDK ${{ matrix.jdk }}"
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 21
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-
- uses: actions/cache@v3
name: "Cache secret key"
id: "cache-secret-cert"
with:
path: ${{ github.workspace }}/.tmp/rsa
key: secret-rsa-${{ runner.os }}-${{ github.run_id }}
- name: "Get sonarcloud token"
if: ${{ github.repository == 'apache/dubbo' }}
run: |
curl "http://dubbo-vm.apache.org:8000/token?workflow_id=${{ github.run_id }}" -o ${{ github.workspace }}/.tmp/encrypted-sonarcloud-token
openssl rsautl -decrypt -in ${{ github.workspace }}/.tmp/encrypted-sonarcloud-token -out ${{ github.workspace }}/.tmp/decrypted-sonarcloud-token -inkey ${{ github.workspace }}/.tmp/rsa/rsa_private.pem
- name: "Test with Maven with SonarCloud Scan"
if: ${{ github.repository == 'apache/dubbo' }}
timeout-minutes: 70
env:
# Needed to get some information about the pull request, if any
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
source ${{ github.workspace }}/.tmp/decrypted-sonarcloud-token
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Pjacoco,jdk15ge-simple,'!jdk15ge',jacoco089 -Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=apache -Dsonar.projectKey=apache_dubbo -DtrimStackTrace=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper -Dsonar.coverage.jacoco.xmlReportPaths=dubbo-test/dubbo-dependencies-all/target/site/jacoco-aggregate/jacoco.xml -Dsonar.login=${SONAR_TOKEN}
- name: "Test with Maven without SonarCloud Scan"
if: ${{ github.repository != 'apache/dubbo' }}
timeout-minutes: 70
run: |
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Pjacoco,jdk15ge-simple,'!jdk15ge',jacoco089 -DtrimStackTrace=false -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Upload coverage result"
uses: actions/upload-artifact@v3
with:
name: coverage-result
path: "**/target/site/**/jacoco.xml"
samples-test-prepare:
needs: check-format
runs-on: ubuntu-latest
env:
JOB_COUNT: 3
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Prepare test list"
run: |
bash ./test/scripts/prepare-test.sh
- name: "Upload test list"
uses: actions/upload-artifact@v3
with:
name: samples-test-list
path: test/jobs
samples-test-job:
needs: [check-format, build-source, samples-test-prepare]
name: "Samples Test on ubuntu-latest (JobId: ${{matrix.job_id}})"
runs-on: ubuntu-latest
timeout-minutes: 90
env:
JAVA_VER: 8
TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt
strategy:
fail-fast: false
matrix:
job_id: [1, 2, 3]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Cache local Maven repository"
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Restore Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-dubbo-snapshot-${{ github.sha }}
${{ runner.os }}-dubbo-snapshot-
- name: "Download test list"
uses: actions/download-artifact@v3
with:
name: samples-test-list
path: test/jobs/
- name: "Set up JDK 8"
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 8
- name: "Init Candidate Versions"
run: |
DUBBO_VERSION="${{needs.build-source.outputs.version}}"
CANDIDATE_VERSIONS="dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION"
echo "CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS" >> $GITHUB_ENV
- name: "Build test image"
run: |
cd test && bash ./build-test-image.sh
- name: "Run tests"
run: cd test && bash ./run-tests.sh
- name: "merge jacoco resule"
run: |
cd test/dubbo-test-jacoco-merger && mvn clean compile exec:java -Dexec.mainClass="org.apache.dubbo.test.JacocoMerge" -Dexec.args="${{github.workspace}}"
- name: "Upload jacoco"
uses: actions/upload-artifact@v3
with:
name: samples-jacoco-result
path: target/jacoco*.exec
- name: "Upload test result"
if: always()
uses: actions/upload-artifact@v3
with:
name: samples-test-result
path: test/jobs/*-result*
samples-test-result:
needs: [check-format, samples-test-job]
if: always()
runs-on: ubuntu-latest
env:
JAVA_VER: 8
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Download test result"
uses: actions/download-artifact@v3
with:
name: samples-test-result
path: test/jobs/
- name: "Merge test result"
run: ./test/scripts/merge-test-results.sh
integration-test-prepare:
needs: check-format
runs-on: ubuntu-latest
env:
JOB_COUNT: 3
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Prepare test list"
run: |
bash ./test/scripts/prepare-test.sh
- name: "Upload test list"
uses: actions/upload-artifact@v3
with:
name: test-list
path: test/jobs
integration-test-job:
needs: [check-format, build-source, integration-test-prepare]
name: "Integration Test on ubuntu-latest (JobId: ${{matrix.job_id}})"
runs-on: ubuntu-latest
timeout-minutes: 90
env:
JAVA_VER: 8
TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt
strategy:
fail-fast: false
matrix:
job_id: [1, 2, 3]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Cache local Maven repository"
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Restore Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-dubbo-snapshot-${{ github.sha }}
${{ runner.os }}-dubbo-snapshot-
- name: "Download test list"
uses: actions/download-artifact@v3
with:
name: test-list
path: test/jobs/
- name: "Set up JDK 8"
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 8
- name: "Init Candidate Versions"
run: |
DUBBO_VERSION="${{needs.build-source.outputs.version}}"
CANDIDATE_VERSIONS="dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION"
echo "CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS" >> $GITHUB_ENV
- name: "Build test image"
run: |
cd test && bash ./build-test-image.sh
- name: "Run tests"
run: cd test && bash ./run-tests.sh
- name: "merge jacoco resule"
run: |
cd test/dubbo-test-jacoco-merger && mvn clean compile exec:java -Dexec.mainClass="org.apache.dubbo.test.JacocoMerge" -Dexec.args="${{github.workspace}}"
- name: "Upload jacoco"
uses: actions/upload-artifact@v3
with:
name: jacoco-result
path: target/jacoco*.exec
- name: "Upload test result"
if: always()
uses: actions/upload-artifact@v3
with:
name: test-result
path: test/jobs/*-result*
integration-test-result:
needs: [check-format, integration-test-job]
if: always()
runs-on: ubuntu-latest
env:
JAVA_VER: 8
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Download test result"
uses: actions/download-artifact@v3
with:
name: test-result
path: test/jobs/
- name: "Merge test result"
run: ./test/scripts/merge-test-results.sh
jacoco-result-merge:
runs-on: ubuntu-latest
needs: [check-format, integration-test-result, samples-test-result, unit-test]
steps:
- uses: actions/checkout@v3
with:
path: "./dubbo"
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
path: "./dubbo-samples"
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
path: "./dubbo-integration-cases"
- name: "Set up JDK 21"
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 21
- name: "Restore class result"
uses: actions/download-artifact@v3
with:
name: "class-file"
path: ${{ github.workspace }}
- name: "Unpack class result"
run: |
cd ${{ github.workspace }}/dubbo
unzip -o ${{ github.workspace }}/class.zip
- name: "Restore jacoco exec"
uses: actions/download-artifact@v3
with:
name: samples-jacoco-result
path: dubbo-samples/target/
- name: "Restore integration jacoco exec"
uses: actions/download-artifact@v3
with:
name: jacoco-result
path: dubbo-integration-cases/target/
- name: "Merge jacoco result"
run: |
cd ${{ github.workspace }}/dubbo-samples/test/dubbo-test-jacoco-merger
mvn clean compile exec:java -Dexec.mainClass="org.apache.dubbo.test.JacocoReport" -Dexec.args="${{github.workspace}}/dubbo-samples ${{github.workspace}}/dubbo"
- name: "Merge samples jacoco result"
run: |
cd ${{ github.workspace }}/dubbo-integration-cases/test/dubbo-test-jacoco-merger
mvn clean compile exec:java -Dexec.mainClass="org.apache.dubbo.test.JacocoReport" -Dexec.args="${{github.workspace}}/dubbo-integration-cases ${{github.workspace}}/dubbo"
- name: "Restore coverage result"
uses: actions/download-artifact@v3
with:
name: coverage-result
path: dubbo/
- name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v3
with:
verbose: true
error-code-inspecting:
needs: check-format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
path: "./dubbo"
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-test-tools'
ref: main
path: "./dubbo-test-tools"
- name: "Set up JDK 21"
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 21
- name: "Compile Dubbo (Linux)"
run: |
cd ${{ github.workspace }}/dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true
- name: "Run Error Code Inspecting"
env:
DUBBO_ECI_REPORT_AS_ERROR: true
run: |
cd ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector
../mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C package exec:java -Ddubbo.eci.report-as-error=${DUBBO_ECI_REPORT_AS_ERROR} -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -Ddubbo.eci.path=${{ github.workspace }}/dubbo
- name: "Upload error code inspection result"
# always() should not be used here, since we don't need to handle the 'canceled' situation.
if: ${{ success() || failure() }}
uses: actions/upload-artifact@v3
with:
name: "error-inspection-result"
path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt
native-image-inspecting:
needs: check-format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
path: "./dubbo"
- name: "Setup GraalVM environment"
uses: graalvm/setup-graalvm@v1
with:
version: '22.3.0'
java-version: '17'
components: 'native-image'
github-token: ${{ secrets.GITHUB_TOKEN }}
native-image-job-reports: 'true'
- name: "Setup Zookeeper environment"
run: |
wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz
tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz
mv apache-zookeeper-3.8.4-bin/conf/zoo_sample.cfg apache-zookeeper-3.8.4-bin/conf/zoo.cfg
apache-zookeeper-3.8.4-bin/bin/zkServer.sh start
- name: "Check environment"
run: |
java --version
native-image --version
- name: "Compile Dubbo (Linux)"
run: |
cd ${{ github.workspace }}/dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true
- name: "Compile and run Dubbo demo for native (Linux)"
run: |
cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider
${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile
nohup ./target/dubbo-demo-native-provider &
cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer
${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile
./target/dubbo-demo-native-consumer

View File

@ -1,502 +0,0 @@
name: Build and Test Scheduled On 3.1
on:
schedule:
- cron: '0 0/6 * * *'
workflow_dispatch:
permissions:
contents: read
env:
FORK_COUNT: 2
FAIL_FAST: 0
SHOW_ERROR_DETAIL: 1
#multi-version size limit
VERSIONS_LIMIT: 4
ALL_REMOTE_VERSION: true
CANDIDATE_VERSIONS: '
spring.version:5.3.24;
spring-boot.version:2.7.6;
'
jobs:
license:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: "3.1"
- name: Check License
uses: apache/skywalking-eyes@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-source:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.dubbo-version.outputs.version }}
steps:
- uses: actions/checkout@v3
with:
ref: "3.1"
path: dubbo
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 8
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
- name: "Build Dubbo with Maven"
run: |
cd ./dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean source:jar install -Pjacoco,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Pack checkstyle file if failure"
if: failure()
run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r
- name: "Upload checkstyle file if failure"
if: failure()
uses: actions/upload-artifact@v3
with:
name: "checkstyle-file"
path: ${{ github.workspace }}/checkstyle.zip
- name: "Calculate Dubbo Version"
id: dubbo-version
run: |
REVISION=`awk '/<revision>[^<]+<\/revision>/{gsub(/<revision>|<\/revision>/,"",$1);print $1;exit;}' ./dubbo/pom.xml`
echo "version=$REVISION" >> $GITHUB_OUTPUT
echo "dubbo version: $REVISION"
unit-test-prepare:
name: " Preparation for Unit Test On ${{ matrix.os }}"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
env:
ZOOKEEPER_VERSION: 3.6.3
steps:
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
- name: "Set up msys2 if necessary"
if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
uses: msys2/setup-msys2@v2
with:
release: false # support cache, see https://github.com/msys2/setup-msys2#context
- name: "Download zookeeper binary archive in Linux OS"
if: ${{ startsWith( matrix.os, 'ubuntu') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
run: |
mkdir -p ${{ github.workspace }}/.tmp/zookeeper
wget -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.stu.edu.tw/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
echo "list the downloaded zookeeper binary archive"
ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
- name: "Download zookeeper binary archive in Windows OS"
if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
shell: msys2 {0}
run: |
mkdir -p ${{ github.workspace }}/.tmp/zookeeper
wget -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.stu.edu.tw/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
echo "list the downloaded zookeeper binary archive"
ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
unit-test:
needs: [build-source, unit-test-prepare]
name: "Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }})"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
jdk: [ 8, 11, 17, 21 ]
env:
DISABLE_FILE_SYSTEM_TEST: true
steps:
- uses: actions/checkout@v3
with:
ref: "3.1"
- name: "Set up JDK ${{ matrix.jdk }}"
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.jdk }}
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-
- name: "Test with Maven with Integration Tests"
timeout-minutes: 70
if: ${{ startsWith( matrix.os, 'ubuntu') }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Test with Maven without Integration Tests"
timeout-minutes: 90
if: ${{ startsWith( matrix.os, 'windows') }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true" -D"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper"
unit-test-fastjson2:
needs: [build-source, unit-test-prepare]
name: "Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }}, Serialization: fastjson2)"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
jdk: [ 8, 11, 17, 21 ]
env:
DISABLE_FILE_SYSTEM_TEST: true
DUBBO_DEFAULT_SERIALIZATION: fastjson2
MAVEN_SUREFIRE_ADD_OPENS: true
steps:
- uses: actions/checkout@v3
- name: "Set up JDK ${{ matrix.jdk }}"
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: ${{ matrix.jdk }}
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-
- name: "Test with Maven with Integration Tests on JDK 8"
timeout-minutes: 70
if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk == '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,'!jdk15ge' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Test with Maven without Integration Tests on JDK 8"
timeout-minutes: 90
if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk == '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P"jacoco,'!jdk15ge'" -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true" -D"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper"
- name: "Test with Maven with Integration Tests"
timeout-minutes: 70
if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk != '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,jdk15ge-simple,'!jdk15ge' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Test with Maven without Integration Tests"
timeout-minutes: 90
if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk != '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P"jacoco,jdk15ge-simple,'!jdk15ge'" -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true" -D"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper"
samples-test-prepare:
runs-on: ubuntu-latest
env:
JOB_COUNT: 5
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Prepare test list"
run: |
bash ./test/scripts/prepare-test.sh
- name: "Upload test list"
uses: actions/upload-artifact@v3
with:
name: samples-test-list
path: test/jobs
samples-test-job:
needs: [build-source, samples-test-prepare]
name: "Samples Test on ubuntu-latest (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})"
runs-on: ubuntu-latest
timeout-minutes: 90
env:
JAVA_VER: ${{matrix.jdk}}
TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt
strategy:
fail-fast: false
matrix:
jdk: [ 8, 11 ]
job_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Cache local Maven repository"
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Restore Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-dubbo-snapshot-${{ github.sha }}
${{ runner.os }}-dubbo-snapshot-
- name: "Download test list"
uses: actions/download-artifact@v3
with:
name: samples-test-list
path: test/jobs/
- name: "Set up JDK ${{matrix.jdk}}"
uses: actions/setup-java@v1
with:
java-version: ${{matrix.jdk}}
- name: "Init Candidate Versions"
run: |
DUBBO_VERSION="${{needs.build-source.outputs.version}}"
CANDIDATE_VERSIONS="dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION"
echo "CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS" >> $GITHUB_ENV
- name: "Build test image"
run: |
cd test && bash ./build-test-image.sh
- name: "Run tests"
run: cd test && bash ./run-tests.sh
- name: "Upload test result"
if: always()
uses: actions/upload-artifact@v3
with:
name: samples-test-result-${{matrix.jdk}}
path: test/jobs/*-result*
samples-test-result:
needs: [samples-test-job]
if: always()
runs-on: ubuntu-latest
env:
JAVA_VER: ${{matrix.jdk}}
strategy:
matrix:
jdk: [ 8, 11 ]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Download test result"
uses: actions/download-artifact@v3
with:
name: samples-test-result-${{matrix.jdk}}
path: test/jobs/
- name: "Merge test result"
run: ./test/scripts/merge-test-results.sh
integration-test-prepare:
runs-on: ubuntu-latest
env:
JOB_COUNT: 5
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Prepare test list"
run: |
bash ./test/scripts/prepare-test.sh
- name: "Upload test list"
uses: actions/upload-artifact@v3
with:
name: integration-test-list
path: test/jobs
integration-test-job:
needs: [build-source, integration-test-prepare]
name: "Integration Test on ubuntu-latest (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})"
runs-on: ubuntu-latest
timeout-minutes: 90
env:
JAVA_VER: ${{matrix.jdk}}
TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt
strategy:
fail-fast: false
matrix:
jdk: [ 8, 11 ]
job_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Cache local Maven repository"
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Restore Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-dubbo-snapshot-${{ github.sha }}
${{ runner.os }}-dubbo-snapshot-
- name: "Download test list"
uses: actions/download-artifact@v3
with:
name: integration-test-list
path: test/jobs/
- name: "Set up JDK ${{matrix.jdk}}"
uses: actions/setup-java@v1
with:
java-version: ${{matrix.jdk}}
- name: "Init Candidate Versions"
run: |
DUBBO_VERSION="${{needs.build-source.outputs.version}}"
CANDIDATE_VERSIONS="dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION"
echo "CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS" >> $GITHUB_ENV
- name: "Build test image"
run: |
cd test && bash ./build-test-image.sh
- name: "Run tests"
run: cd test && bash ./run-tests.sh
- name: "Upload test result"
if: always()
uses: actions/upload-artifact@v3
with:
name: integration-test-result-${{matrix.jdk}}
path: test/jobs/*-result*
integration-test-result:
needs: [integration-test-job]
if: always()
runs-on: ubuntu-latest
env:
JAVA_VER: ${{matrix.jdk}}
strategy:
matrix:
jdk: [ 8, 11 ]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Download test result"
uses: actions/download-artifact@v3
with:
name: integration-test-result-${{matrix.jdk}}
path: test/jobs/
- name: "Merge test result"
run: ./test/scripts/merge-test-results.sh
error-code-inspecting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: "3.1"
path: "./dubbo"
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-test-tools'
ref: main
path: "./dubbo-test-tools"
- name: "Set up JDK 21"
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 21
- name: "Compile Dubbo (Linux)"
run: |
cd ${{ github.workspace }}/dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true
- name: "Run Error Code Inspecting"
env:
DUBBO_ECI_REPORT_AS_ERROR: true
run: |
cd ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector
../mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C package exec:java -Ddubbo.eci.report-as-error=${DUBBO_ECI_REPORT_AS_ERROR} -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -Ddubbo.eci.path=${{ github.workspace }}/dubbo
- name: "Upload error code inspection result"
# always() should not be used here, since we don't need to handle the 'canceled' situation.
if: ${{ success() || failure() }}
uses: actions/upload-artifact@v3
with:
name: "error-inspection-result"
path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt
native-image-inspecting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: "3.1"
path: "./dubbo"
- name: "Setup GraalVM environment"
uses: graalvm/setup-graalvm@v1
with:
version: '22.3.0'
java-version: '17'
components: 'native-image'
github-token: ${{ secrets.GITHUB_TOKEN }}
native-image-job-reports: 'true'
- name: "Setup Zookeeper environment"
run: |
wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz
tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz
mv apache-zookeeper-3.8.4-bin/conf/zoo_sample.cfg apache-zookeeper-3.8.4-bin/conf/zoo.cfg
apache-zookeeper-3.8.4-bin/bin/zkServer.sh start
- name: "Check environment"
run: |
java --version
native-image --version
- name: "Compile Dubbo (Linux)"
run: |
cd ${{ github.workspace }}/dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true
- name: "Compile and run Dubbo demo for native (Linux)"
run: |
cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider
${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile
nohup ./target/dubbo-demo-native-provider &
cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer
${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile
./target/dubbo-demo-native-consumer

View File

@ -1,502 +0,0 @@
name: Build and Test Scheduled On 3.2
on:
schedule:
- cron: '0 0/6 * * *'
workflow_dispatch:
permissions:
contents: read
env:
FORK_COUNT: 2
FAIL_FAST: 0
SHOW_ERROR_DETAIL: 1
#multi-version size limit
VERSIONS_LIMIT: 4
ALL_REMOTE_VERSION: true
CANDIDATE_VERSIONS: '
spring.version:5.3.24;
spring-boot.version:2.7.6;
'
jobs:
license:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: "3.2"
- name: Check License
uses: apache/skywalking-eyes@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-source:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.dubbo-version.outputs.version }}
steps:
- uses: actions/checkout@v3
with:
ref: "3.2"
path: dubbo
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 8
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
- name: "Build Dubbo with Maven"
run: |
cd ./dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean source:jar install -Pjacoco,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Pack checkstyle file if failure"
if: failure()
run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r
- name: "Upload checkstyle file if failure"
if: failure()
uses: actions/upload-artifact@v3
with:
name: "checkstyle-file"
path: ${{ github.workspace }}/checkstyle.zip
- name: "Calculate Dubbo Version"
id: dubbo-version
run: |
REVISION=`awk '/<revision>[^<]+<\/revision>/{gsub(/<revision>|<\/revision>/,"",$1);print $1;exit;}' ./dubbo/pom.xml`
echo "version=$REVISION" >> $GITHUB_OUTPUT
echo "dubbo version: $REVISION"
unit-test-prepare:
name: " Preparation for Unit Test On ${{ matrix.os }}"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
env:
ZOOKEEPER_VERSION: 3.6.3
steps:
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
- name: "Set up msys2 if necessary"
if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
uses: msys2/setup-msys2@v2
with:
release: false # support cache, see https://github.com/msys2/setup-msys2#context
- name: "Download zookeeper binary archive in Linux OS"
if: ${{ startsWith( matrix.os, 'ubuntu') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
run: |
mkdir -p ${{ github.workspace }}/.tmp/zookeeper
wget -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.stu.edu.tw/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
echo "list the downloaded zookeeper binary archive"
ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
- name: "Download zookeeper binary archive in Windows OS"
if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
shell: msys2 {0}
run: |
mkdir -p ${{ github.workspace }}/.tmp/zookeeper
wget -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.stu.edu.tw/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
echo "list the downloaded zookeeper binary archive"
ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
unit-test:
needs: [build-source, unit-test-prepare]
name: "Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }})"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
jdk: [ 8, 11, 17, 21 ]
env:
DISABLE_FILE_SYSTEM_TEST: true
steps:
- uses: actions/checkout@v3
with:
ref: "3.2"
- name: "Set up JDK ${{ matrix.jdk }}"
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.jdk }}
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-
- name: "Test with Maven with Integration Tests"
timeout-minutes: 70
if: ${{ startsWith( matrix.os, 'ubuntu') }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Test with Maven without Integration Tests"
timeout-minutes: 90
if: ${{ startsWith( matrix.os, 'windows') }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true" -D"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper"
unit-test-fastjson2:
needs: [build-source, unit-test-prepare]
name: "Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }}, Serialization: fastjson2)"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
jdk: [ 8, 11, 17, 21 ]
env:
DISABLE_FILE_SYSTEM_TEST: true
DUBBO_DEFAULT_SERIALIZATION: fastjson2
MAVEN_SUREFIRE_ADD_OPENS: true
steps:
- uses: actions/checkout@v3
- name: "Set up JDK ${{ matrix.jdk }}"
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: ${{ matrix.jdk }}
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-
- name: "Test with Maven with Integration Tests on JDK 8"
timeout-minutes: 70
if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk == '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,'!jdk15ge' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Test with Maven without Integration Tests on JDK 8"
timeout-minutes: 90
if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk == '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P"jacoco,'!jdk15ge'" -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true" -D"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper"
- name: "Test with Maven with Integration Tests"
timeout-minutes: 70
if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk != '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,jdk15ge-simple,'!jdk15ge' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Test with Maven without Integration Tests"
timeout-minutes: 90
if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk != '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P"jacoco,jdk15ge-simple,'!jdk15ge'" -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true" -D"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper"
samples-test-prepare:
runs-on: ubuntu-latest
env:
JOB_COUNT: 5
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Prepare test list"
run: |
bash ./test/scripts/prepare-test.sh
- name: "Upload test list"
uses: actions/upload-artifact@v3
with:
name: samples-test-list
path: test/jobs
samples-test-job:
needs: [build-source, samples-test-prepare]
name: "Samples Test on ubuntu-latest (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})"
runs-on: ubuntu-latest
timeout-minutes: 90
env:
JAVA_VER: ${{matrix.jdk}}
TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt
strategy:
fail-fast: false
matrix:
jdk: [ 8, 11, 17, 21 ]
job_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Cache local Maven repository"
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Restore Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-dubbo-snapshot-${{ github.sha }}
${{ runner.os }}-dubbo-snapshot-
- name: "Download test list"
uses: actions/download-artifact@v3
with:
name: samples-test-list
path: test/jobs/
- name: "Set up JDK ${{matrix.jdk}}"
uses: actions/setup-java@v1
with:
java-version: ${{matrix.jdk}}
- name: "Init Candidate Versions"
run: |
DUBBO_VERSION="${{needs.build-source.outputs.version}}"
CANDIDATE_VERSIONS="dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION"
echo "CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS" >> $GITHUB_ENV
- name: "Build test image"
run: |
cd test && bash ./build-test-image.sh
- name: "Run tests"
run: cd test && bash ./run-tests.sh
- name: "Upload test result"
if: always()
uses: actions/upload-artifact@v3
with:
name: samples-test-result-${{matrix.jdk}}
path: test/jobs/*-result*
samples-test-result:
needs: [samples-test-job]
if: always()
runs-on: ubuntu-latest
env:
JAVA_VER: ${{matrix.jdk}}
strategy:
matrix:
jdk: [ 8, 11, 17, 21 ]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Download test result"
uses: actions/download-artifact@v3
with:
name: samples-test-result-${{matrix.jdk}}
path: test/jobs/
- name: "Merge test result"
run: ./test/scripts/merge-test-results.sh
integration-test-prepare:
runs-on: ubuntu-latest
env:
JOB_COUNT: 5
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Prepare test list"
run: |
bash ./test/scripts/prepare-test.sh
- name: "Upload test list"
uses: actions/upload-artifact@v3
with:
name: integration-test-list
path: test/jobs
integration-test-job:
needs: [build-source, integration-test-prepare]
name: "Integration Test on ubuntu-latest (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})"
runs-on: ubuntu-latest
timeout-minutes: 90
env:
JAVA_VER: ${{matrix.jdk}}
TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt
strategy:
fail-fast: false
matrix:
jdk: [ 8, 11, 17, 21 ]
job_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Cache local Maven repository"
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Restore Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-dubbo-snapshot-${{ github.sha }}
${{ runner.os }}-dubbo-snapshot-
- name: "Download test list"
uses: actions/download-artifact@v3
with:
name: integration-test-list
path: test/jobs/
- name: "Set up JDK ${{matrix.jdk}}"
uses: actions/setup-java@v1
with:
java-version: ${{matrix.jdk}}
- name: "Init Candidate Versions"
run: |
DUBBO_VERSION="${{needs.build-source.outputs.version}}"
CANDIDATE_VERSIONS="dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION"
echo "CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS" >> $GITHUB_ENV
- name: "Build test image"
run: |
cd test && bash ./build-test-image.sh
- name: "Run tests"
run: cd test && bash ./run-tests.sh
- name: "Upload test result"
if: always()
uses: actions/upload-artifact@v3
with:
name: integration-test-result-${{matrix.jdk}}
path: test/jobs/*-result*
integration-test-result:
needs: [integration-test-job]
if: always()
runs-on: ubuntu-latest
env:
JAVA_VER: ${{matrix.jdk}}
strategy:
matrix:
jdk: [ 8, 11, 17, 21 ]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Download test result"
uses: actions/download-artifact@v3
with:
name: integration-test-result-${{matrix.jdk}}
path: test/jobs/
- name: "Merge test result"
run: ./test/scripts/merge-test-results.sh
error-code-inspecting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: "3.2"
path: "./dubbo"
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-test-tools'
ref: main
path: "./dubbo-test-tools"
- name: "Set up JDK 21"
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 21
- name: "Compile Dubbo (Linux)"
run: |
cd ${{ github.workspace }}/dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true
- name: "Run Error Code Inspecting"
env:
DUBBO_ECI_REPORT_AS_ERROR: true
run: |
cd ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector
../mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C package exec:java -Ddubbo.eci.report-as-error=${DUBBO_ECI_REPORT_AS_ERROR} -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -Ddubbo.eci.path=${{ github.workspace }}/dubbo
- name: "Upload error code inspection result"
# always() should not be used here, since we don't need to handle the 'canceled' situation.
if: ${{ success() || failure() }}
uses: actions/upload-artifact@v3
with:
name: "error-inspection-result"
path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt
native-image-inspecting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: "3.2"
path: "./dubbo"
- name: "Setup GraalVM environment"
uses: graalvm/setup-graalvm@v1
with:
version: '22.3.0'
java-version: '17'
components: 'native-image'
github-token: ${{ secrets.GITHUB_TOKEN }}
native-image-job-reports: 'true'
- name: "Setup Zookeeper environment"
run: |
wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz
tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz
mv apache-zookeeper-3.8.4-bin/conf/zoo_sample.cfg apache-zookeeper-3.8.4-bin/conf/zoo.cfg
apache-zookeeper-3.8.4-bin/bin/zkServer.sh start
- name: "Check environment"
run: |
java --version
native-image --version
- name: "Compile Dubbo (Linux)"
run: |
cd ${{ github.workspace }}/dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true
- name: "Compile and run Dubbo demo for native (Linux)"
run: |
cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider
${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile
nohup ./target/dubbo-demo-native-provider &
cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer
${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile
./target/dubbo-demo-native-consumer

View File

@ -1,502 +0,0 @@
name: Build and Test Scheduled On 3.3
on:
schedule:
- cron: '0 0/6 * * *'
workflow_dispatch:
permissions:
contents: read
env:
FORK_COUNT: 2
FAIL_FAST: 0
SHOW_ERROR_DETAIL: 1
#multi-version size limit
VERSIONS_LIMIT: 4
ALL_REMOTE_VERSION: true
CANDIDATE_VERSIONS: '
spring.version:5.3.24;
spring-boot.version:2.7.6;
'
jobs:
license:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: "3.3"
- name: Check License
uses: apache/skywalking-eyes@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-source:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.dubbo-version.outputs.version }}
steps:
- uses: actions/checkout@v3
with:
ref: "3.3"
path: dubbo
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 21
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
- name: "Build Dubbo with Maven"
run: |
cd ./dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean source:jar install -Pjacoco,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Pack checkstyle file if failure"
if: failure()
run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r
- name: "Upload checkstyle file if failure"
if: failure()
uses: actions/upload-artifact@v3
with:
name: "checkstyle-file"
path: ${{ github.workspace }}/checkstyle.zip
- name: "Calculate Dubbo Version"
id: dubbo-version
run: |
REVISION=`awk '/<revision>[^<]+<\/revision>/{gsub(/<revision>|<\/revision>/,"",$1);print $1;exit;}' ./dubbo/pom.xml`
echo "version=$REVISION" >> $GITHUB_OUTPUT
echo "dubbo version: $REVISION"
unit-test-prepare:
name: " Preparation for Unit Test On ${{ matrix.os }}"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
env:
ZOOKEEPER_VERSION: 3.6.3
steps:
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
- name: "Set up msys2 if necessary"
if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
uses: msys2/setup-msys2@v2
with:
release: false # support cache, see https://github.com/msys2/setup-msys2#context
- name: "Download zookeeper binary archive in Linux OS"
if: ${{ startsWith( matrix.os, 'ubuntu') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
run: |
mkdir -p ${{ github.workspace }}/.tmp/zookeeper
wget -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.stu.edu.tw/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
echo "list the downloaded zookeeper binary archive"
ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
- name: "Download zookeeper binary archive in Windows OS"
if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
shell: msys2 {0}
run: |
mkdir -p ${{ github.workspace }}/.tmp/zookeeper
wget -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.stu.edu.tw/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
echo "list the downloaded zookeeper binary archive"
ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
unit-test:
needs: [build-source, unit-test-prepare]
name: "Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }})"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
jdk: [ 8, 11, 17, 21 ]
env:
DISABLE_FILE_SYSTEM_TEST: true
steps:
- uses: actions/checkout@v3
with:
ref: "3.3"
- name: "Set up JDK ${{ matrix.jdk }}"
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.jdk }}
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-
- name: "Test with Maven with Integration Tests"
timeout-minutes: 70
if: ${{ startsWith( matrix.os, 'ubuntu') }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Test with Maven without Integration Tests"
timeout-minutes: 90
if: ${{ startsWith( matrix.os, 'windows') }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true" -D"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper"
unit-test-fastjson2:
needs: [build-source, unit-test-prepare]
name: "Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }}, Serialization: fastjson2)"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
jdk: [ 8, 11, 17, 21 ]
env:
DISABLE_FILE_SYSTEM_TEST: true
DUBBO_DEFAULT_SERIALIZATION: fastjson2
MAVEN_SUREFIRE_ADD_OPENS: true
steps:
- uses: actions/checkout@v3
- name: "Set up JDK ${{ matrix.jdk }}"
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: ${{ matrix.jdk }}
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-
- name: "Test with Maven with Integration Tests on JDK 8"
timeout-minutes: 70
if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk == '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,'!jdk15ge' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Test with Maven without Integration Tests on JDK 8"
timeout-minutes: 90
if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk == '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P"jacoco,'!jdk15ge'" -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true" -D"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper"
- name: "Test with Maven with Integration Tests"
timeout-minutes: 70
if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk != '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,jdk15ge-simple,'!jdk15ge' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Test with Maven without Integration Tests"
timeout-minutes: 90
if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk != '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P"jacoco,jdk15ge-simple,'!jdk15ge'" -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true" -D"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper"
samples-test-prepare:
runs-on: ubuntu-latest
env:
JOB_COUNT: 5
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Prepare test list"
run: |
bash ./test/scripts/prepare-test.sh
- name: "Upload test list"
uses: actions/upload-artifact@v3
with:
name: samples-test-list
path: test/jobs
samples-test-job:
needs: [build-source, samples-test-prepare]
name: "Samples Test on ubuntu-latest (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})"
runs-on: ubuntu-latest
timeout-minutes: 90
env:
JAVA_VER: ${{matrix.jdk}}
TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt
strategy:
fail-fast: false
matrix:
jdk: [ 8, 11, 17, 21 ]
job_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Cache local Maven repository"
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Restore Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-dubbo-snapshot-${{ github.sha }}
${{ runner.os }}-dubbo-snapshot-
- name: "Download test list"
uses: actions/download-artifact@v3
with:
name: samples-test-list
path: test/jobs/
- name: "Set up JDK ${{matrix.jdk}}"
uses: actions/setup-java@v1
with:
java-version: ${{matrix.jdk}}
- name: "Init Candidate Versions"
run: |
DUBBO_VERSION="${{needs.build-source.outputs.version}}"
CANDIDATE_VERSIONS="dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION"
echo "CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS" >> $GITHUB_ENV
- name: "Build test image"
run: |
cd test && bash ./build-test-image.sh
- name: "Run tests"
run: cd test && bash ./run-tests.sh
- name: "Upload test result"
if: always()
uses: actions/upload-artifact@v3
with:
name: samples-test-result-${{matrix.jdk}}
path: test/jobs/*-result*
samples-test-result:
needs: [samples-test-job]
if: always()
runs-on: ubuntu-latest
env:
JAVA_VER: ${{matrix.jdk}}
strategy:
matrix:
jdk: [ 8, 11, 17, 21 ]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Download test result"
uses: actions/download-artifact@v3
with:
name: samples-test-result-${{matrix.jdk}}
path: test/jobs/
- name: "Merge test result"
run: ./test/scripts/merge-test-results.sh
integration-test-prepare:
runs-on: ubuntu-latest
env:
JOB_COUNT: 5
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Prepare test list"
run: |
bash ./test/scripts/prepare-test.sh
- name: "Upload test list"
uses: actions/upload-artifact@v3
with:
name: integration-test-list
path: test/jobs
integration-test-job:
needs: [build-source, integration-test-prepare]
name: "Integration Test on ubuntu-latest (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})"
runs-on: ubuntu-latest
timeout-minutes: 90
env:
JAVA_VER: ${{matrix.jdk}}
TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt
strategy:
fail-fast: false
matrix:
jdk: [ 8, 11, 17, 21 ]
job_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Cache local Maven repository"
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Restore Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-dubbo-snapshot-${{ github.sha }}
${{ runner.os }}-dubbo-snapshot-
- name: "Download test list"
uses: actions/download-artifact@v3
with:
name: integration-test-list
path: test/jobs/
- name: "Set up JDK ${{matrix.jdk}}"
uses: actions/setup-java@v1
with:
java-version: ${{matrix.jdk}}
- name: "Init Candidate Versions"
run: |
DUBBO_VERSION="${{needs.build-source.outputs.version}}"
CANDIDATE_VERSIONS="dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION"
echo "CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS" >> $GITHUB_ENV
- name: "Build test image"
run: |
cd test && bash ./build-test-image.sh
- name: "Run tests"
run: cd test && bash ./run-tests.sh
- name: "Upload test result"
if: always()
uses: actions/upload-artifact@v3
with:
name: integration-test-result-${{matrix.jdk}}
path: test/jobs/*-result*
integration-test-result:
needs: [integration-test-job]
if: always()
runs-on: ubuntu-latest
env:
JAVA_VER: ${{matrix.jdk}}
strategy:
matrix:
jdk: [ 8, 11, 17, 21 ]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Download test result"
uses: actions/download-artifact@v3
with:
name: integration-test-result-${{matrix.jdk}}
path: test/jobs/
- name: "Merge test result"
run: ./test/scripts/merge-test-results.sh
error-code-inspecting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: "3.3"
path: "./dubbo"
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-test-tools'
ref: main
path: "./dubbo-test-tools"
- name: "Set up JDK 21"
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 21
- name: "Compile Dubbo (Linux)"
run: |
cd ${{ github.workspace }}/dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true
- name: "Run Error Code Inspecting"
env:
DUBBO_ECI_REPORT_AS_ERROR: true
run: |
cd ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector
../mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C package exec:java -Ddubbo.eci.report-as-error=${DUBBO_ECI_REPORT_AS_ERROR} -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -Ddubbo.eci.path=${{ github.workspace }}/dubbo
- name: "Upload error code inspection result"
# always() should not be used here, since we don't need to handle the 'canceled' situation.
if: ${{ success() || failure() }}
uses: actions/upload-artifact@v3
with:
name: "error-inspection-result"
path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt
native-image-inspecting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: "3.3"
path: "./dubbo"
- name: "Setup GraalVM environment"
uses: graalvm/setup-graalvm@v1
with:
version: '22.3.0'
java-version: '17'
components: 'native-image'
github-token: ${{ secrets.GITHUB_TOKEN }}
native-image-job-reports: 'true'
- name: "Setup Zookeeper environment"
run: |
wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz
tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz
mv apache-zookeeper-3.8.4-bin/conf/zoo_sample.cfg apache-zookeeper-3.8.4-bin/conf/zoo.cfg
apache-zookeeper-3.8.4-bin/bin/zkServer.sh start
- name: "Check environment"
run: |
java --version
native-image --version
- name: "Compile Dubbo (Linux)"
run: |
cd ${{ github.workspace }}/dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true
- name: "Compile and run Dubbo demo for native (Linux)"
run: |
cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider
${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile
nohup ./target/dubbo-demo-native-provider &
cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer
${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile
./target/dubbo-demo-native-consumer

View File

@ -1,497 +0,0 @@
name: Release Test
on:
push:
branches:
- '**-release'
workflow_dispatch:
permissions:
contents: read
env:
FORK_COUNT: 2
FAIL_FAST: 0
SHOW_ERROR_DETAIL: 1
#multi-version size limit
VERSIONS_LIMIT: 4
ALL_REMOTE_VERSION: true
CANDIDATE_VERSIONS: '
spring.version:5.3.24;
spring-boot.version:2.7.6;
'
jobs:
license:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Check License
uses: apache/skywalking-eyes@main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-source:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.dubbo-version.outputs.version }}
steps:
- uses: actions/checkout@v3
with:
path: dubbo
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 8
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
- name: "Build Dubbo with Maven"
run: |
cd ./dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean source:jar install -Pjacoco,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Pack checkstyle file if failure"
if: failure()
run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r
- name: "Upload checkstyle file if failure"
if: failure()
uses: actions/upload-artifact@v3
with:
name: "checkstyle-file"
path: ${{ github.workspace }}/checkstyle.zip
- name: "Calculate Dubbo Version"
id: dubbo-version
run: |
REVISION=`awk '/<revision>[^<]+<\/revision>/{gsub(/<revision>|<\/revision>/,"",$1);print $1;exit;}' ./dubbo/pom.xml`
echo "version=$REVISION" >> $GITHUB_OUTPUT
echo "dubbo version: $REVISION"
unit-test-prepare:
name: " Preparation for Unit Test On ${{ matrix.os }}"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
env:
ZOOKEEPER_VERSION: 3.6.3
steps:
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
- name: "Set up msys2 if necessary"
if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
uses: msys2/setup-msys2@v2
with:
release: false # support cache, see https://github.com/msys2/setup-msys2#context
- name: "Download zookeeper binary archive in Linux OS"
if: ${{ startsWith( matrix.os, 'ubuntu') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
run: |
mkdir -p ${{ github.workspace }}/.tmp/zookeeper
wget -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.stu.edu.tw/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
echo "list the downloaded zookeeper binary archive"
ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
- name: "Download zookeeper binary archive in Windows OS"
if: ${{ startsWith( matrix.os, 'windows') && steps.cache-zookeeper.outputs.cache-hit != 'true' }}
shell: msys2 {0}
run: |
mkdir -p ${{ github.workspace }}/.tmp/zookeeper
wget -c https://archive.apache.org/dist/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c https://apache.website-solution.net/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.stu.edu.tw/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://ftp.jaist.ac.jp/pub/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://apache.mirror.cdnetworks.com/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz ||
wget -c http://mirror.apache-kr.org/apache/zookeeper/zookeeper-${{ env.ZOOKEEPER_VERSION }}/apache-zookeeper-${{ env.ZOOKEEPER_VERSION }}-bin.tar.gz -O ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
echo "list the downloaded zookeeper binary archive"
ls -al ${{ github.workspace }}/.tmp/zookeeper/apache-zookeeper-bin.tar.gz
unit-test:
needs: [build-source, unit-test-prepare]
name: "Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }})"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
jdk: [ 8, 11, 17, 21 ]
env:
DISABLE_FILE_SYSTEM_TEST: true
steps:
- uses: actions/checkout@v3
- name: "Set up JDK ${{ matrix.jdk }}"
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.jdk }}
distribution: 'zulu'
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-
- name: "Test with Maven with Integration Tests"
timeout-minutes: 70
if: ${{ startsWith( matrix.os, 'ubuntu') }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Test with Maven without Integration Tests"
timeout-minutes: 90
if: ${{ startsWith( matrix.os, 'windows') }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true" -D"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper"
unit-test-fastjson2:
needs: [build-source, unit-test-prepare]
name: "Unit Test On ${{ matrix.os }} (JDK: ${{ matrix.jdk }}, Serialization: fastjson2)"
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, windows-latest ]
jdk: [ 8, 11, 17, 21 ]
env:
DISABLE_FILE_SYSTEM_TEST: true
DUBBO_DEFAULT_SERIALIZATION: fastjson2
MAVEN_SUREFIRE_ADD_OPENS: true
steps:
- uses: actions/checkout@v3
- name: "Set up JDK ${{ matrix.jdk }}"
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: ${{ matrix.jdk }}
- uses: actions/cache@v3
name: "Cache local Maven repository"
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- uses: actions/cache@v3
name: "Cache zookeeper binary archive"
id: "cache-zookeeper"
with:
path: ${{ github.workspace }}/.tmp/zookeeper
key: zookeeper-${{ runner.os }}-${{ env.ZOOKEEPER_VERSION }}
restore-keys: |
zookeeper-${{ runner.os }}-
- name: "Test with Maven with Integration Tests on JDK 8"
timeout-minutes: 70
if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk == '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,'!jdk15ge' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Test with Maven without Integration Tests on JDK 8"
timeout-minutes: 90
if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk == '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P"jacoco,'!jdk15ge'" -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true" -D"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper"
- name: "Test with Maven with Integration Tests"
timeout-minutes: 70
if: ${{ startsWith( matrix.os, 'ubuntu') && matrix.jdk != '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -Pjacoco,jdk15ge-simple,'!jdk15ge' -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true -DembeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper
- name: "Test with Maven without Integration Tests"
timeout-minutes: 90
if: ${{ startsWith( matrix.os, 'windows') && matrix.jdk != '8' }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean test verify -P"jacoco,jdk15ge-simple,'!jdk15ge'" -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true" -D"embeddedZookeeperPath=${{ github.workspace }}/.tmp/zookeeper"
samples-test-prepare:
runs-on: ubuntu-latest
env:
JOB_COUNT: 5
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Prepare test list"
run: |
bash ./test/scripts/prepare-test.sh
- name: "Upload test list"
uses: actions/upload-artifact@v3
with:
name: samples-test-list
path: test/jobs
samples-test-job:
needs: [build-source, samples-test-prepare]
name: "Samples Test on ubuntu-latest (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})"
runs-on: ubuntu-latest
timeout-minutes: 90
env:
JAVA_VER: ${{matrix.jdk}}
TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt
strategy:
fail-fast: false
matrix:
jdk: [ 8, 11, 17, 21 ]
job_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Cache local Maven repository"
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Restore Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-dubbo-snapshot-${{ github.sha }}
${{ runner.os }}-dubbo-snapshot-
- name: "Download test list"
uses: actions/download-artifact@v3
with:
name: samples-test-list
path: test/jobs/
- name: "Set up JDK ${{matrix.jdk}}"
uses: actions/setup-java@v1
with:
java-version: ${{matrix.jdk}}
- name: "Init Candidate Versions"
run: |
DUBBO_VERSION="${{needs.build-source.outputs.version}}"
CANDIDATE_VERSIONS="dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION"
echo "CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS" >> $GITHUB_ENV
- name: "Build test image"
run: |
cd test && bash ./build-test-image.sh
- name: "Run tests"
run: cd test && bash ./run-tests.sh
- name: "Upload test result"
if: always()
uses: actions/upload-artifact@v3
with:
name: samples-test-result-${{matrix.jdk}}
path: test/jobs/*-result*
samples-test-result:
needs: [samples-test-job]
if: always()
runs-on: ubuntu-latest
env:
JAVA_VER: ${{matrix.jdk}}
strategy:
matrix:
jdk: [ 8, 11, 17, 21 ]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-samples'
ref: master
- name: "Download test result"
uses: actions/download-artifact@v3
with:
name: samples-test-result-${{matrix.jdk}}
path: test/jobs/
- name: "Merge test result"
run: ./test/scripts/merge-test-results.sh
integration-test-prepare:
runs-on: ubuntu-latest
env:
JOB_COUNT: 5
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Prepare test list"
run: |
bash ./test/scripts/prepare-test.sh
- name: "Upload test list"
uses: actions/upload-artifact@v3
with:
name: integration-test-list
path: test/jobs
integration-test-job:
needs: [build-source, integration-test-prepare]
name: "Integration Test on ubuntu-latest (JobId: ${{matrix.job_id}} JavaVer: ${{matrix.jdk}})"
runs-on: ubuntu-latest
timeout-minutes: 90
env:
JAVA_VER: ${{matrix.jdk}}
TEST_CASE_FILE: jobs/testjob_${{matrix.job_id}}.txt
strategy:
fail-fast: false
matrix:
jdk: [ 8, 11, 17, 21 ]
job_id: [1, 2, 3, 4, 5]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Cache local Maven repository"
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
${{ runner.os }}-maven-
- name: "Restore Dubbo cache"
uses: actions/cache@v3
with:
path: ~/.m2/repository/org/apache/dubbo
key: ${{ runner.os }}-dubbo-snapshot-${{ github.sha }}-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-dubbo-snapshot-${{ github.sha }}
${{ runner.os }}-dubbo-snapshot-
- name: "Download test list"
uses: actions/download-artifact@v3
with:
name: integration-test-list
path: test/jobs/
- name: "Set up JDK ${{matrix.jdk}}"
uses: actions/setup-java@v1
with:
java-version: ${{matrix.jdk}}
- name: "Init Candidate Versions"
run: |
DUBBO_VERSION="${{needs.build-source.outputs.version}}"
CANDIDATE_VERSIONS="dubbo.version:$DUBBO_VERSION;compiler.version:$DUBBO_VERSION;$CANDIDATE_VERSIONS;dubbo.compiler.version:$DUBBO_VERSION"
echo "CANDIDATE_VERSIONS=$CANDIDATE_VERSIONS" >> $GITHUB_ENV
- name: "Build test image"
run: |
cd test && bash ./build-test-image.sh
- name: "Run tests"
run: cd test && bash ./run-tests.sh
- name: "Upload test result"
if: always()
uses: actions/upload-artifact@v3
with:
name: integration-test-result-${{matrix.jdk}}
path: test/jobs/*-result*
integration-test-result:
needs: [integration-test-job]
if: always()
runs-on: ubuntu-latest
env:
JAVA_VER: ${{matrix.jdk}}
strategy:
matrix:
jdk: [ 8, 11, 17, 21 ]
steps:
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-integration-cases'
ref: main
- name: "Download test result"
uses: actions/download-artifact@v3
with:
name: integration-test-result-${{matrix.jdk}}
path: test/jobs/
- name: "Merge test result"
run: ./test/scripts/merge-test-results.sh
error-code-inspecting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
path: "./dubbo"
- uses: actions/checkout@v3
with:
repository: 'apache/dubbo-test-tools'
ref: main
path: "./dubbo-test-tools"
- name: "Set up JDK 21"
uses: actions/setup-java@v3
with:
java-version: 21
distribution: 'zulu'
- name: "Compile Dubbo (Linux)"
run: |
cd ${{ github.workspace }}/dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true
- name: "Run Error Code Inspecting"
env:
DUBBO_ECI_REPORT_AS_ERROR: true
run: |
cd ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector
../mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C package exec:java -Ddubbo.eci.report-as-error=${DUBBO_ECI_REPORT_AS_ERROR} -Dmaven.test.skip=true -Dmaven.test.skip.exec=true -Ddubbo.eci.path=${{ github.workspace }}/dubbo
- name: "Upload error code inspection result"
# always() should not be used here, since we don't need to handle the 'canceled' situation.
if: ${{ success() || failure() }}
uses: actions/upload-artifact@v3
with:
name: "error-inspection-result"
path: ${{ github.workspace }}/dubbo-test-tools/dubbo-error-code-inspector/error-inspection-result.txt
native-image-inspecting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
path: "./dubbo"
- name: "Setup GraalVM environment"
uses: graalvm/setup-graalvm@v1
with:
version: '22.3.0'
java-version: '17'
components: 'native-image'
github-token: ${{ secrets.GITHUB_TOKEN }}
native-image-job-reports: 'true'
- name: "Setup Zookeeper environment"
run: |
wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz
tar -zxvf apache-zookeeper-3.8.4-bin.tar.gz
mv apache-zookeeper-3.8.4-bin/conf/zoo_sample.cfg apache-zookeeper-3.8.4-bin/conf/zoo.cfg
apache-zookeeper-3.8.4-bin/bin/zkServer.sh start
- name: "Check environment"
run: |
java --version
native-image --version
- name: "Compile Dubbo (Linux)"
run: |
cd ${{ github.workspace }}/dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean install -DskipTests=true -DskipIntegrationTests=true -Dcheckstyle.skip=true -Dcheckstyle_unix.skip=true -Drat.skip=true -Dmaven.javadoc.skip=true
- name: "Compile and run Dubbo demo for native (Linux)"
run: |
cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-provider
${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile
nohup ./target/dubbo-demo-native-provider &
cd ${{ github.workspace }}/dubbo/dubbo-demo/dubbo-demo-native/dubbo-demo-native-consumer
${{ github.workspace }}/dubbo/mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast -T 2C clean package -P native -Dmaven.test.skip=true native:compile
./target/dubbo-demo-native-consumer

9
.gitignore vendored
View File

@ -1,6 +1,7 @@
# maven ignore # maven ignore
target/ target/
*.jar *.jar
!.mvn/wrapper/*
*.war *.war
*.zip *.zip
*.tar *.tar
@ -11,8 +12,6 @@ target/
.settings/ .settings/
.project .project
.classpath .classpath
.externalToolBuilders
maven-eclipse.xml
# idea ignore # idea ignore
.idea/ .idea/
@ -49,9 +48,3 @@ dubbo-demo/dubbo-demo-triple/build/*
# global registry center # global registry center
.tmp .tmp
.git.exec.error
# log files generated by testcase.
dubbo-rpc/dubbo-rpc-api/custom-access.log*

View File

@ -1,235 +0,0 @@
header:
license:
spdx-id: Apache-2.0
content: |
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
paths-ignore:
- '**/*.versionsBackup'
- '**/.idea/'
- '**/*.iml'
- '**/.settings/*'
- '**/.classpath'
- '**/.project'
- '**/target/**'
- '**/generated/**'
- '**/*.log'
- '**/codestyle/*'
- '**/resources/META-INF/**'
- '**/resources/mockito-extensions/**'
- '**/*.proto'
- '**/*.cache'
- '**/*.txt'
- '**/*.load'
- '**/*.flex'
- '**/*.fc'
- '**/*.javascript'
- '**/*.properties'
- '**/*.sh'
- '**/*.bat'
- '**/*.md'
- '**/*.svg'
- '**/*.png'
- '**/*.json'
- '**/*.conf'
- '**/*.ftl'
- '**/*.tpl'
- '**/*.factories'
- '**/*.handlers'
- '**/*.schemas'
- '**/*.nojekyll'
- '.git/'
- '.github/**'
- '**/.gitignore'
- '**/.helmignore'
- '.repository/'
- 'compiler/**'
- '.gitmodules'
- '.mvn'
- 'mvnw'
- 'mvnw.cmd'
- 'LICENSE'
- 'NOTICE'
- 'CNAME'
- 'Jenkinsfile'
- '**/vendor/**'
- '**/src/test/resources/certs/**'
- '**/src/test/resources/definition/**'
- 'dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocal.java'
- 'dubbo-common/src/main/java/org/apache/dubbo/common/threadlocal/InternalThreadLocalMap.java'
- 'dubbo-common/src/main/java/org/apache/dubbo/common/timer/HashedWheelTimer.java'
- 'dubbo-common/src/main/java/org/apache/dubbo/common/timer/Timeout.java'
- 'dubbo-common/src/main/java/org/apache/dubbo/common/timer/Timer.java'
- 'dubbo-common/src/main/java/org/apache/dubbo/common/timer/TimerTask.java'
- 'dubbo-common/src/main/java/org/apache/dubbo/common/utils/CIDRUtils.java'
- 'dubbo-common/src/main/java/org/apache/dubbo/common/utils/Utf8Utils.java'
- 'dubbo-config/dubbo-config-spring/src/test/java/org/apache/dubbo/config/spring/EmbeddedZooKeeper.java'
- 'dubbo-test/dubbo-test-common/src/main/java/org/apache/dubbo/test/common/utils/TestSocketUtils.java'
- 'dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TriHttp2RemoteFlowController.java'
- 'dubbo-common/src/main/java/org/apache/dubbo/common/threadpool/serial/SerializingExecutor.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/AbstractAotMojo.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/AbstractDependencyFilterMojo.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/CommandLineBuilder.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/DependencyFilter.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/Exclude.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/ExcludeFilter.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/FilterableDependency.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/Include.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/IncludeFilter.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/JavaCompilerPluginConfiguration.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/JavaExecutable.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/JavaProcessExecutor.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/MatchingGroupIdFilter.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunArguments.java'
- 'dubbo-maven-plugin/src/main/java/org/apache/dubbo/maven/plugin/aot/RunProcess.java'
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/generate/BasicJsonWriter.java'
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/generate/ExecutableMode.java'
- 'dubbo-native/src/main/java/org/apache/dubbo/aot/generate/MemberCategory.java'
- 'dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboMergingDigest.java'
- 'dubbo-metrics/dubbo-metrics-api/src/main/java/org/apache/dubbo/metrics/aggregate/DubboAbstractTDigest.java'
comment: on-failure
license-location-threshold: 130
dependency:
files:
- pom.xml
- dubbo-dependencies-bom/pom.xml
licenses:
- name: com.alibaba.spring:spring-context-support
license: Apache-2.0
- name: com.fasterxml.jackson.core:jackson-annotations
license: Apache-2.0
- name: com.fasterxml.jackson.core:jackson-core
license: Apache-2.0
- name: com.fasterxml.jackson.core:jackson-databind
license: Apache-2.0
- name: com.fasterxml.jackson.dataformat:jackson-dataformat-yaml
license: Apache-2.0
- name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310
license: Apache-2.0
- name: com.google.code.gson:gson
license: Apache-2.0
- name: com.google.guava:listenablefuture
license: Apache-2.0
- name: com.salesforce.servicelibs:grpc-contrib
license: BSD 3-clause
- name: com.squareup.okhttp3:logging-interceptor
license: Apache-2.0
- name: com.squareup.okhttp3:okhttp
license: Apache-2.0
- name: com.squareup.okio:okio
license: Apache-2.0
- name: com.sun.xml.fastinfoset:FastInfoset
license: Apache-2.0
- name: io.envoyproxy.controlplane:api
license: Apache-2.0
- name: io.swagger:swagger-annotations
license: Apache-2.0
- name: io.swagger:swagger-models
license: Apache-2.0
- name: org.springframework.boot:spring-boot
license: Apache-2.0
- name: org.springframework.boot:spring-boot-actuator
license: Apache-2.0
- name: org.springframework.boot:spring-boot-autoconfigure
license: Apache-2.0
- name: org.springframework.boot:spring-boot-configuration-processor
license: Apache-2.0
- name: org.springframework.boot:spring-boot-starter
license: Apache-2.0
- name: org.springframework.boot:spring-boot-starter-actuator
license: Apache-2.0
- name: org.springframework.boot:spring-boot-starter-logging
license: Apache-2.0
- name: org.springframework.boot:spring-boot-starter-tomcat
license: Apache-2.0
- name: org.springframework.boot:spring-boot-starter-web
license: Apache-2.0
- name: org.slf4j:slf4j-api
license: MIT
- name: org.slf4j:slf4j-log4j12
license: MIT
- name: org.jboss.resteasy:resteasy-jaxrs
license: Apache-2.0
- name: org.jboss.resteasy:resteasy-client
license: Apache-2.0
- name: org.jboss.resteasy:resteasy-netty4
license: Apache-2.0
- name: org.jboss.resteasy:resteasy-jdk-http
license: Apache-2.0
- name: org.jboss.resteasy:resteasy-jackson-provider
license: Apache-2.0
- name: org.jboss.resteasy:resteasy-jaxb-provider
license: Apache-2.0
- name: net.jcip:jcip-annotations
license: Apache-2.0
- name: org.apache.zookeeper:zookeeper
license: Apache-2.0
- name: org.apache.zookeeper:zookeeper-jute
license: Apache-2.0
- name: net.bytebuddy:byte-buddy
license: Apache-2.0
- name: javax.enterprise:cdi-api
license: Apache-2.0
- name: org.codehaus.plexus:plexus-component-annotations
license: Apache-2.0
- name: org.slf4j:jcl-over-slf4j
license: Apache-2.0
- name: org.slf4j:jul-to-slf4j
license: Apache-2.0
- name: org.codehaus.plexus:plexus-interpolation
license: Apache-2.0
- name: org.sonatype.plexus:plexus-sec-dispatcher
license: Apache-2.0
- name: org.sonatype.plexus:plexus-cipher
license: Apache-2.0
- name: com.google.protobuf:protobuf-java
license: BSD 3-clause
- name: com.google.protobuf:protobuf-java-util
license: BSD 3-clause
# multi license
- name: org.javassist:javassist
license: Apache-2.0
- name: javax.annotation:javax.annotation-api
license: CDDL-1.0
- name: com.salesforce.servicelibs:jprotoc
license: CDDL-1.0
- name: org.checkerframework:checker-compat-qual
license: MIT
- name: ch.qos.logback:logback-classic
license: EPL-1.0
- name: ch.qos.logback:logback-core
license: EPL-1.0
- name: javax.servlet:javax.servlet-api
license: CDDL-1.1
- name: com.sun.activation:javax.activation
license: CDDL-1.1
- name: javax.activation:activation
license: CDDL-1.1
- name: jakarta.annotation:jakarta.annotation-api
license: EPL-2.0
- name: org.glassfish:jakarta.el
license: EPL-2.0
- name: org.jboss.spec.javax.annotation:jboss-annotations-api_1.2_spec
license: CDDL-1.1
- name: org.jboss.spec.javax.ws.rs:jboss-jaxrs-api_2.1_spec
license: EPL-2.0
- name: org.jboss.spec.javax.annotation:jboss-annotations-api_1.3_spec
license: EPL-2.0
excludes:
- name: javax.xml.bind:jsr173_api

BIN
.mvn/wrapper/maven-wrapper.jar vendored Executable file

Binary file not shown.

View File

@ -1,18 +1 @@
# Licensed to the Apache Software Foundation (ASF) under one distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.7/apache-maven-3.8.7-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar

30
.travis.yml Normal file
View File

@ -0,0 +1,30 @@
sudo: false # faster builds
os: linux
dist: focal
arch: arm64-graviton2
virt: lxd
group: edge
language: java
jdk: openjdk11
cache:
directories:
- $HOME/.m2
install: true
branches:
only:
- '3.0'
before_script:
- rm -rf $HOME/.m2/repository/org/glassfish/javax.el/3.0.1-b08
script: if [[ "${TRAVIS_EVENT_TYPE}" == "cron" ]]; then travis_wait 60 ./mvnw --batch-mode -U -q -e --no-transfer-progress clean test -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true; fi
after_success:
- bash <(curl -s https://codecov.io/bash)
after_failure:
- echo "build failed!"

View File

@ -101,7 +101,7 @@ check 2.7.5 milestone for details.
* In consumer side the app cannot catch the exception from provider that is configured serialization="kryo". #4238 * In consumer side the app cannot catch the exception from provider that is configured serialization="kryo". #4238
* fix StringUtils#isBlank #4725 * fix StringUtils#isBlank #4725
* when the interfaceName of the Reference annotation has duplicated,the exception is puzzled #4160 * when the interfaceName of the Reference annotation has duplicated,the exception is puzzled #4160
* when anonymity bean is defined in spring contextdubbo throw npe # * when anonymity bean is defined in spirng contextdubbo throw npe #
* add Thread ContextClassLoader #4712 * add Thread ContextClassLoader #4712
* Fix judgment ipv4 address #4729 * Fix judgment ipv4 address #4729
* The compilation of static methods should be excluded when generating the proxy. #4647 * The compilation of static methods should be excluded when generating the proxy. #4647
@ -184,7 +184,7 @@ check 2.7.5 milestone for details.
- Add a script to check dependencies license. [#3840](https://github.com/apache/dubbo/issues/3840) - Add a script to check dependencies license. [#3840](https://github.com/apache/dubbo/issues/3840)
- Change DynamicConfiguration definition to better adapt to Apollo's namespace storage model.[#3266](https://github.com/apache/dubbo/issues/3266) - Change DynamicConfiguration definition to better adapt to Apollo's namespace storage model.[#3266](https://github.com/apache/dubbo/issues/3266)
- use equal explicit class to replace anonymous class [#4027](https://github.com/apache/dubbo/issues/4027) - use equal explicit class to replace anonymous class [#4027](https://github.com/apache/dubbo/issues/4027)
- Separate Constants.java into some SubConstants Class [#3137](https://github.com/apache/dubbo/issues/3137) - Seperate Constants.java into some SubConstants Class [#3137](https://github.com/apache/dubbo/issues/3137)
- Need to enhance DecodeableRpcResult error message [#3994](https://github.com/apache/dubbo/issues/3994) - Need to enhance DecodeableRpcResult error message [#3994](https://github.com/apache/dubbo/issues/3994)
- Provide more meaningful binary releases. [#2491](https://github.com/apache/dubbo/issues/2491) - Provide more meaningful binary releases. [#2491](https://github.com/apache/dubbo/issues/2491)
- remove useless module-dubbo-test-integration [#3573](https://github.com/apache/dubbo/issues/3573) - remove useless module-dubbo-test-integration [#3573](https://github.com/apache/dubbo/issues/3573)
@ -211,7 +211,7 @@ check 2.7.5 milestone for details.
- Fix consumer will generate wrong stackTrace. [#4137](https://github.com/apache/dubbo/issues/4137) - Fix consumer will generate wrong stackTrace. [#4137](https://github.com/apache/dubbo/issues/4137)
- nacos registry serviceName may conflict. [#4111](https://github.com/apache/dubbo/issues/4111) - nacos registry serviceName may conflict. [#4111](https://github.com/apache/dubbo/issues/4111)
- The client loses the listener when the network is reconnected. [#4115](https://github.com/apache/dubbo/issues/4115) - The client loses the listener when the network is reconnected. [#4115](https://github.com/apache/dubbo/issues/4115)
- fix registry urls increase forever when recreate reference proxy. [#4109](https://github.com/apache/dubbo/issues/4109) - fix registery urls increase forever when recreate reference proxy. [#4109](https://github.com/apache/dubbo/issues/4109)
- In dubbo 2.7.1the watcher processor of zookeeper client throw Nullpointexception. [#3866](https://github.com/apache/dubbo/issues/3866) - In dubbo 2.7.1the watcher processor of zookeeper client throw Nullpointexception. [#3866](https://github.com/apache/dubbo/issues/3866)
- ReferenceConfig initialized not changed to false once subscribe throws exception [#4068](https://github.com/apache/dubbo/issues/4068) - ReferenceConfig initialized not changed to false once subscribe throws exception [#4068](https://github.com/apache/dubbo/issues/4068)
- dubbo registry extension compatibility with dubbo 2.6.x. [#3882](https://github.com/apache/dubbo/issues/3882) - dubbo registry extension compatibility with dubbo 2.6.x. [#3882](https://github.com/apache/dubbo/issues/3882)
@ -400,7 +400,7 @@ Enhancement / New feature
* tag route. #3065 * tag route. #3065
* Use Netty4 as default Netty version. #3029 * Use Netty4 as default Netty version. #3029
* upporting Java 8 Date/Time type when serializing with Kryo #3519 * upporting Java 8 Date/Time type when serializing with Kryo #3519
* support config telnet #3511 * supoort config telnet #3511
* add annotation driven in MethodConfig and ArgumentConfig #2603 * add annotation driven in MethodConfig and ArgumentConfig #2603
* add nacos-registry module #3296 * add nacos-registry module #3296
* add `protocol` attribute in `@Rerefence` #3555 * add `protocol` attribute in `@Rerefence` #3555
@ -416,7 +416,7 @@ BugFix
* SPI entires dup by 3 times #3315 * SPI entires dup by 3 times #3315
* fix Consumer throws RpcException after RegistryDirectory notify in high QPS #2016 * fix Consumer throws RpcException after RegistryDirectory notify in high QPS #2016
* fix NPE in @Reference when using Junit to test dubbo service #3429 * fix NPE in @Reference when using Junit to test dubbo service #3429
* fix consumer always catch java.lang.reflect.UndeclaredThrowableException for any exception throws in provider #3386 * fix consuer always catch java.lang.reflect.UndeclaredThrowableException for any exception throws in provider #3386
* fix the priority of `DubboConfigConfigurationSelector ` #2897 * fix the priority of `DubboConfigConfigurationSelector ` #2897
* fix `@Rerefence#parameters()` not work #2301 * fix `@Rerefence#parameters()` not work #2301

View File

@ -1,51 +0,0 @@
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*
*/
pipeline {
agent {
label 'ubuntu'
}
tools {
maven 'maven_3_latest'
jdk 'jdk_11_latest'
}
stages {
stage('Code Quality') {
steps {
echo 'Checking Code Quality on SonarCloud'
script {
// Main parameters
def sonarcloudParams=""
if ( env.BRANCH_NAME.startsWith("PR-") ) {
// this is a pull request
withCredentials([string(credentialsId: 'sonarcloud-token', variable: 'SONAR_TOKEN')]) {
sh './mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean verify sonar:sonar -Dmaven.test.skip=true -Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=apache -Dsonar.projectKey=apache_dubbo -Dsonar.coverage.jacoco.xmlReportPaths=dubbo-test/dubbo-dependencies-all/target/site/jacoco-aggregate/jacoco.xml -Dsonar.pullrequest.branch=${CHANGE_BRANCH} -Dsonar.pullrequest.base=${CHANGE_TARGET} -Dsonar.pullrequest.key=${CHANGE_ID} -Dsonar.login=${SONAR_TOKEN}'
}
} else {
// this is just a branch
withCredentials([string(credentialsId: 'sonarcloud-token', variable: 'SONAR_TOKEN')]) {
sh './mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress --fail-fast clean verify sonar:sonar -Dmaven.test.skip=true -Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=apache -Dsonar.projectKey=apache_dubbo -Dsonar.coverage.jacoco.xmlReportPaths=dubbo-test/dubbo-dependencies-all/target/site/jacoco-aggregate/jacoco.xml -Dsonar.branch.name=${BRANCH_NAME} -Dsonar.login=${SONAR_TOKEN}'
}
}
}
}
}
}
}

6
NOTICE
View File

@ -1,5 +1,5 @@
Apache Dubbo Apache Dubbo
Copyright 2018-2024 The Apache Software Foundation Copyright 2018-2023 The Apache Software Foundation
This product includes software developed at This product includes software developed at
The Apache Software Foundation (http://www.apache.org/). The Apache Software Foundation (http://www.apache.org/).
@ -12,7 +12,3 @@ Please visit the Netty web site for more information:
* http://netty.io/ * http://netty.io/
Copyright 2014 The Netty Project Copyright 2014 The Netty Project
This product contains code form the t-digest Project:
The code for the t-digest was originally authored by Ted Dunning
Adrien Grand contributed the heart of the AVLTreeDigest (https://github.com/jpountz)

133
README.md
View File

@ -1,15 +1,18 @@
# Apache Dubbo Project # Apache Dubbo Project
[![Build and Test For PR](https://github.com/apache/dubbo/actions/workflows/build-and-test-pr.yml/badge.svg)](https://github.com/apache/dubbo/actions/workflows/build-and-test-pr.yml) [![Build Status](https://github.com/apache/dubbo/workflows/Build%20and%20Test%20For%20Dubbo%203/badge.svg?branch=3.0)](https://github.com/apache/dubbo/actions/workflows/build-and-test-3.yml?query=branch%3A3.0)
[![Codecov](https://codecov.io/gh/apache/dubbo/branch/3.2/graph/badge.svg)](https://codecov.io/gh/apache/dubbo) [![Codecov](https://codecov.io/gh/apache/dubbo/branch/3.0/graph/badge.svg)](https://codecov.io/gh/apache/dubbo)
![Maven](https://img.shields.io/maven-central/v/org.apache.dubbo/dubbo.svg) ![Maven](https://img.shields.io/maven-central/v/org.apache.dubbo/dubbo.svg)
![License](https://img.shields.io/github/license/alibaba/dubbo.svg) ![License](https://img.shields.io/github/license/alibaba/dubbo.svg)
[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/apache/dubbo.svg)](http://isitmaintained.com/project/apache/dubbo "Average time to resolve an issue") [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/apache/dubbo.svg)](http://isitmaintained.com/project/apache/dubbo "Average time to resolve an issue")
[![Percentage of issues still open](http://isitmaintained.com/badge/open/apache/dubbo.svg)](http://isitmaintained.com/project/apache/dubbo "Percentage of issues still open") [![Percentage of issues still open](http://isitmaintained.com/badge/open/apache/dubbo.svg)](http://isitmaintained.com/project/apache/dubbo "Percentage of issues still open")
[![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Apache%20Dubbo%20is%20a%20high-performance%2C%20java%20based%2C%20open%20source%20RPC%20framework.&url=http://dubbo.apache.org/&via=ApacheDubbo&hashtags=rpc,java,dubbo,micro-service)
[![Twitter Follow](https://img.shields.io/twitter/follow/ApacheDubbo.svg?label=Follow&style=social&logoWidth=0)](https://twitter.com/intent/follow?screen_name=ApacheDubbo)
[![Gitter](https://badges.gitter.im/alibaba/dubbo.svg)](https://gitter.im/alibaba/dubbo?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
Apache Dubbo is a high-performance, Java-based open-source RPC framework. Please visit the [official site](http://dubbo.apache.org) for the quick start guide and documentation, as well as the [wiki](https://github.com/apache/dubbo/wiki) for news, FAQ, and release notes. Apache Dubbo is a high-performance, Java-based open-source RPC framework. Please visit the [official site](http://dubbo.apache.org) for the quick start guide and documentation, as well as the [wiki](https://github.com/apache/dubbo/wiki) for news, FAQ, and release notes.
We are now collecting Dubbo user info to help us to improve Dubbo further. Kindly support us by providing your usage information on [Wanted: who's using dubbo](https://github.com/apache/dubbo/discussions/13842), thanks :) We are now collecting Dubbo user info to help us to improve Dubbo further. Kindly support us by providing your usage information on [issue#9436: Wanted: who's using dubbo](https://github.com/apache/dubbo/issues/9436), thanks :)
## Architecture ## Architecture
@ -26,20 +29,20 @@ We are now collecting Dubbo user info to help us to improve Dubbo further. Kindl
## Getting started ## Getting started
The following code snippet comes from [Dubbo Samples](https://github.com/apache/dubbo-samples.git). You may clone the sample project and step into the `dubbo-samples-api` subdirectory before proceeding. The following code snippet comes from [Dubbo Samples](https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-api). You may clone the sample project and step into the `dubbo-samples-api` subdirectory before proceeding.
```bash ```bash
git clone https://github.com/apache/dubbo-samples.git git clone https://github.com/apache/dubbo-samples.git
cd dubbo-samples/1-basic/dubbo-samples-api cd dubbo-samples/dubbo-samples-api
``` ```
There's a [README](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-api/README.md) file under `dubbo-samples-api` directory. We recommend referencing the samples in that directory by following the below-mentioned instructions: There's a [README](https://github.com/apache/dubbo-samples/tree/master/dubbo-samples-api/README.md) file under `dubbo-samples-api` directory. We recommend referencing the samples in that directory by following the below-mentioned instructions:
### Maven dependency ### Maven dependency
```xml ```xml
<properties> <properties>
<dubbo.version>3.2.13-SNAPSHOT</dubbo.version> <dubbo.version>3.0.10</dubbo.version>
</properties> </properties>
<dependencies> <dependencies>
@ -67,7 +70,7 @@ public interface GreetingsService {
} }
``` ```
*See [api/GreetingsService.java](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/api/GreetingsService.java) on GitHub.* *See [api/GreetingsService.java](https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/api/GreetingsService.java) on GitHub.*
### Implement service interface for the provider ### Implement service interface for the provider
@ -84,7 +87,7 @@ public class GreetingsServiceImpl implements GreetingsService {
} }
``` ```
*See [provider/GreetingsServiceImpl.java](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java) on GitHub.* *See [provider/GreetingsServiceImpl.java](https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/GreetingsServiceImpl.java) on GitHub.*
### Start service provider ### Start service provider
@ -116,7 +119,7 @@ public class Application {
} }
``` ```
*See [provider/Application.java](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-spring-xml/src/main/java/org/apache/dubbo/samples/provider/Application.java) on GitHub.* *See [provider/Application.java](https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/provider/Application.java) on GitHub.*
### Build and run the provider ### Build and run the provider
@ -150,7 +153,7 @@ public class Application {
} }
} }
``` ```
*See [client/Application.java](https://github.com/apache/dubbo-samples/blob/389cd612f1ea57ee6e575005b32f195c442c35a2/1-basic/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/client/Application.java) on GitHub.* *See [consumer/Application.java](https://github.com/apache/dubbo-samples/blob/master/dubbo-samples-api/src/main/java/org/apache/dubbo/samples/client/Application.java) on GitHub.*
### Build and run the consumer ### Build and run the consumer
@ -164,10 +167,10 @@ The consumer will print out `hi, dubbo` on the screen.
### Next steps ### Next steps
* [Your first Dubbo application](https://dubbo.apache.org/en/blog/2018/08/07/dubbo-101/) - A 101 tutorial to reveal more details, with the same code above. * [Your first Dubbo application](https://dubbo.apache.org/blog/2018/08/07/dubbo-101/) - A 101 tutorial to reveal more details, with the same code above.
* [Dubbo user manual](https://dubbo.apache.org/en/overview/what/) - How to use Dubbo and all its features. * [Dubbo user manual](https://dubbo.apache.org/docs/v2.7/user/preface/background/) - How to use Dubbo and all its features.
* [Dubbo developer guide](https://dubbo.apache.org/en/docs3-v2/java-sdk/) - How to involve in Dubbo development. * [Dubbo developer guide](https://dubbo.apache.org/docs/v2.7/dev/build/) - How to involve in Dubbo development.
* [Dubbo admin manual](https://dubbo.apache.org/en/docs/v2.7/admin/ops/) - How to admin and manage Dubbo services. * [Dubbo admin manual](https://dubbo.apache.org/docs/v2.7/admin/install/provider-demo/) - How to admin and manage Dubbo services.
## Building ## Building
@ -177,91 +180,55 @@ If you want to try out the cutting-edge features, you can build with the followi
mvn clean install mvn clean install
``` ```
## Recommended Test Environment
To avoid intermittent test failures (i.e., flaky tests), it is recommended to have a machine or virtual machine with the following specifications:
* Minimum of 2CPUs.
* Minimum of 2Gb of RAM.
### How does the Dubbo Community collaborate?
The Dubbo Community primarily communicates on GitHub through issues, discussions, and pull requests.
- Issues: We use issues to track bugs and tasks. Any **work-related** item is associated with an issue.
- Discussions: We use discussions for questions, early proposals, and announcements. Any **idea-related** item is associated with a discussion.
- Pull Requests: We use pull requests to merge a set of changes from contributors into Dubbo.
We have also implemented [a project board](https://github.com/orgs/apache/projects/337) to monitor all the items.
Any essential changes should be discussed on the mailing list before they happen.
### Seeking for help
If you have questions such as:
- What is Dubbo?
- How do I use Dubbo?
- Why did an unexpected result occur?
Please start a discussion at https://github.com/apache/dubbo/discussions.
However, if you encounter the following situations:
- You're certain there's a bug that Dubbo needs to fix,
- You believe a feature could be enhanced,
- You have a detailed proposal for improving Dubbo,
Please open an issue at https://github.com/apache/dubbo/issues.
To ask effective questions, we recommend reading **[How To Ask Questions The Smart Way](https://github.com/selfteaching/How-To-Ask-Questions-The-Smart-Way/blob/master/How-To-Ask-Questions-The-Smart-Way.md)** first.
### Contribution
- Browse the "help wanted" tasks in the [Dubbo project board](https://github.com/orgs/apache/projects/337).
- Participate in discussions on the mailing list. See the subscription [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide).
- Respond to queries in the [discussions](https://github.com/apache/dubbo/issues).
- Resolve bugs reported in [issues](https://github.com/apache/dubbo/issues) and send us a pull request.
- Review existing [pull requests](https://github.com/apache/dubbo/pulls).
- Enhance the [website](https://github.com/apache/dubbo-website). We typically need:
- Blog posts
- Translations for documentation
- Use cases showcasing Dubbo integration in enterprise systems.
- Improve the [dubbo-admin](https://github.com/apache/dubbo-admin).
- Contribute to the projects listed in the [ecosystem](https://github.com/apache/?q=dubbo&type=all&language=&sort=).
- Any other forms of contribution not listed above are also welcome.
- If you're interested in contributing, please send an email to [dev@dubbo.apache.org](mailto:dev@dubbo.apache.org) to let us know!
For further details, please refer our [guide](https://github.com/apache/dubbo/blob/master/CONTRIBUTING.md) about how to contribute Dubbo.
## Reporting bugs
Please follow the [template](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md) for reporting any issues.
## Reporting a security vulnerability
Please report security vulnerabilities to [us](mailto:security@dubbo.apache.org) privately.
## Contact ## Contact
* Mailing list: * Mailing list:
* dev list: for dev/user discussion. [subscribe](mailto:dev-subscribe@dubbo.apache.org), [unsubscribe](mailto:dev-unsubscribe@dubbo.apache.org), [archive](https://lists.apache.org/list.html?dev@dubbo.apache.org), [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide) * dev list: for dev/user discussion. [subscribe](mailto:dev-subscribe@dubbo.apache.org), [unsubscribe](mailto:dev-unsubscribe@dubbo.apache.org), [archive](https://lists.apache.org/list.html?dev@dubbo.apache.org), [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide)
* Bugs: [Issues](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md) * Bugs: [Issues](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md)
* Gitter: [Gitter channel](https://gitter.im/alibaba/dubbo) * Gitter: [Gitter channel](https://gitter.im/alibaba/dubbo)
* Twitter: [@ApacheDubbo](https://twitter.com/ApacheDubbo) * Twitter: [@ApacheDubbo](https://twitter.com/ApacheDubbo)
## Contributing
See [CONTRIBUTING](https://github.com/apache/dubbo/blob/master/CONTRIBUTING.md) for details on submitting patches and the contribution workflow.
### How can I contribute?
* Take a look at issues with tags marked [`Good first issue`](https://github.com/apache/dubbo/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) or [`Help wanted`](https://github.com/apache/dubbo/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22).
* Join the discussion on the mailing list, subscription [guide](https://github.com/apache/dubbo/wiki/Mailing-list-subscription-guide).
* Answer questions on [issues](https://github.com/apache/dubbo/issues).
* Fix bugs reported on [issues](https://github.com/apache/dubbo/issues), and send us a pull request.
* Review the existing [pull request](https://github.com/apache/dubbo/pulls).
* Improve the [website](https://github.com/apache/dubbo-website), typically we need
* blog post
* translation on documentation
* use cases around the integration of Dubbo in enterprise systems.
* Improve the [dubbo-admin/dubbo-monitor](https://github.com/apache/dubbo-admin).
* Contribute to the projects listed in [ecosystem](https://github.com/dubbo).
* Other forms of contribution not explicitly enumerated above.
* If you would like to contribute, please send an email to dev@dubbo.apache.org to let us know!
## Reporting bugs
Please follow the [template](https://github.com/apache/dubbo/issues/new?template=dubbo-issue-report-template.md) for reporting any issues.
## Reporting a security vulnerability
Please report security vulnerabilities to [us](mailto:security@dubbo.apache.org) privately.
## Dubbo ecosystem ## Dubbo ecosystem
* [Dubbo Ecosystem Entry](https://github.com/apache?utf8=%E2%9C%93&q=dubbo&type=&language=) - A GitHub group `dubbo` to gather all Dubbo relevant projects not appropriate in [apache](https://github.com/apache) group yet * [Dubbo Ecosystem Entry](https://github.com/apache?utf8=%E2%9C%93&q=dubbo&type=&language=) - A GitHub group `dubbo` to gather all Dubbo relevant projects not appropriate in [apache](https://github.com/apache) group yet
* [Dubbo Website](https://github.com/apache/dubbo-website) - Apache Dubbo official website * [Dubbo Website](https://github.com/apache/dubbo-website) - Apache Dubbo official website
* [Dubbo Samples](https://github.com/apache/dubbo-samples) - samples for Apache Dubbo * [Dubbo Samples](https://github.com/apache/dubbo-samples) - samples for Apache Dubbo
* [Dubbo Spring Boot](https://github.com/apache/dubbo-spring-boot-project) - Spring Boot Project for Dubbo
* [Dubbo Admin](https://github.com/apache/dubbo-admin) - The reference implementation for Dubbo admin * [Dubbo Admin](https://github.com/apache/dubbo-admin) - The reference implementation for Dubbo admin
* [Dubbo Awesome](https://github.com/apache/dubbo-awesome) - Dubbo's slides and video links in Meetup * [Dubbo Awesome](https://github.com/apache/dubbo-awesome) - Dubbo's slides and video links in Meetup
#### Language #### Language
* [Go](https://github.com/apache/dubbo-go) (recommended) * [Go](https://github.com/dubbo/dubbo-go) (recommended)
* [Rust](https://github.com/apache/dubbo-rust)
* [Node.js](https://github.com/apache/dubbo-js) * [Node.js](https://github.com/apache/dubbo-js)
* [Python](https://github.com/dubbo/py-client-for-apache-dubbo) * [Python](https://github.com/dubbo/py-client-for-apache-dubbo)
* [PHP](https://github.com/apache/dubbo-php-framework) * [PHP](https://github.com/apache/dubbo-php-framework)
@ -269,4 +236,4 @@ Please report security vulnerabilities to [us](mailto:security@dubbo.apache.org)
## License ## License
Apache Dubbo software is licensed under the Apache License Version 2.0. See the [LICENSE](https://github.com/apache/dubbo/blob/master/LICENSE) file for details. Apache Dubbo software is licenced under the Apache License Version 2.0. See the [LICENSE](https://github.com/apache/dubbo/blob/master/LICENSE) file for details.

View File

@ -5,15 +5,13 @@
Below is a table that shows versions that we accept security fixes. Below is a table that shows versions that we accept security fixes.
| Version | Supported | | Version | Supported |
|---------| ------------------ | | ------- | ------------------ |
| 3.3.x | :white_check_mark: | | 3.0.x | :white_check_mark: |
| 3.2.x | :white_check_mark: | | 2.7.x | :white_check_mark: |
| 3.1.x | :white_check_mark: | | 2.6.x | :white_check_mark: |
| 3.0.x | :x: |
| 2.7.x | :x: |
| 2.6.x | :x: |
| 2.5.x | :x: | | 2.5.x | :x: |
## Reporting a Vulnerability ## Reporting a Vulnerability
The Apache Software Foundation takes a rigorous standpoint in annihilating the security issues in its software projects. Apache Dubbo is highly sensitive and forthcoming to issues pertaining to its features and functionality. The Apache Software Foundation takes a rigorous standpoint in annihilating the security issues in its software projects. Apache Dubbo is highly sensitive and forthcoming to issues pertaining to its features and functionality.

View File

@ -1,34 +0,0 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
#
codecov:
require_ci_to_pass: false
notify:
wait_for_ci: false
coverage:
status:
# pull-requests only
patch:
default:
threshold: 0.1%
ignore:
- "**/dubbo-demo/**"
- "**/dubbo-compiler/**"
- "**/dubbo-test/**"
- "**/dubbo-compatible/**"
- "**/dubbo-native/**"
- "**/dubbo-native-plugin/**"
- "**/dubbo-common/src/main/java/org/apache/dubbo/common/json/*.java" # internal JSON impl is deprecate, ignore test coverage for them
- "**/dubbo-config/dubbo-config-spring/src/main/java/org/apache/dubbo/config/spring/AnnotationBean.java" # Deprecated

View File

@ -5,6 +5,5 @@
<suppressions> <suppressions>
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]com[\\/]alibaba[\\/]com[\\/]caucho[\\/]hessian" checks=".*"/> <suppress files="[\\/]src[\\/]main[\\/]java[\\/]com[\\/]alibaba[\\/]com[\\/]caucho[\\/]hessian" checks=".*"/>
<suppress files="[\\/]build[\\/]generated[\\/]source[\\/]proto" checks=".*"/> <suppress files="[\\/]build[\\/]generated[\\/]source[\\/]proto" checks=".*"/>
<suppress files="[\\/]target[\\/]generated-sources[\\/]protobuf" checks=".*"/>
<suppress files="Yylex\.java" checks="AvoidEscapedUnicodeCharacters"/> <suppress files="Yylex\.java" checks="AvoidEscapedUnicodeCharacters"/>
</suppressions> </suppressions>

View File

@ -13,77 +13,69 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<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"> <project xmlns="http://maven.apache.org/POM/4.0.0"
<modelVersion>4.0.0</modelVersion> 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>
<groupId>org.apache.dubbo</groupId> <groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-build-tools</artifactId> <artifactId>dubbo-build-tools</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<properties> <properties>
<maven.deploy.skip>true</maven.deploy.skip> <maven.deploy.skip>true</maven.deploy.skip>
<spotless-maven-plugin.version>2.43.0</spotless-maven-plugin.version> </properties>
<spotless.action>check</spotless.action>
<dubbo-shared-resources.version>1.0.0</dubbo-shared-resources.version>
<palantirJavaFormat.version>2.38.0</palantirJavaFormat.version>
</properties>
<profiles> <build>
<profile>
<id>java11+</id>
<activation>
<jdk>[11,)</jdk>
</activation>
<build>
<!--- newer versions of plugins requires JDK 11 -->
<plugins> <plugins>
<plugin> <plugin>
<groupId>com.diffplug.spotless</groupId> <groupId>org.apache.rat</groupId>
<artifactId>spotless-maven-plugin</artifactId> <artifactId>apache-rat-plugin</artifactId>
<version>${spotless-maven-plugin.version}</version> <version>0.13</version>
<configuration> <executions>
<java> <execution>
<palantirJavaFormat> <id>verify.rat</id>
<version>${palantirJavaFormat.version}</version> <phase>verify</phase>
</palantirJavaFormat> <goals>
<removeUnusedImports /> <goal>check</goal>
<importOrder> </goals>
<file>dubbo-importorder.txt</file> </execution>
</importOrder> </executions>
<licenseHeader> <configuration>
<file>checkstyle-header.txt</file> <excludes>
</licenseHeader> <exclude>**/*.versionsBackup</exclude>
</java> <exclude>**/.idea/</exclude>
<pom> <exclude>**/*.iml</exclude>
<sortPom> <exclude>**/*.txt</exclude>
<expandEmptyElements>false</expandEmptyElements> <exclude>**/*.load</exclude>
<spaceBeforeCloseEmptyElement>true</spaceBeforeCloseEmptyElement> <exclude>**/*.flex</exclude>
</sortPom> <exclude>**/*.fc</exclude>
</pom> <exclude>**/*.javascript</exclude>
<upToDateChecking> <exclude>**/*.properties</exclude>
<enabled>true</enabled> <exclude>**/*.thrift</exclude>
</upToDateChecking> <exclude>**/*.sh</exclude>
</configuration> <exclude>**/*.bat</exclude>
<dependencies> <exclude>**/*.md</exclude>
<dependency> <exclude>.git/</exclude>
<groupId>com.alibaba</groupId> <exclude>.gitignore</exclude>
<artifactId>dubbo-shared-resources</artifactId> <exclude>.repository/</exclude>
<version>${dubbo-shared-resources.version}</version> <exclude>**/.settings/*</exclude>
</dependency> <exclude>**/.classpath</exclude>
</dependencies> <exclude>**/.project</exclude>
<executions> <exclude>**/target/**</exclude>
<execution> <exclude>**/generated/**</exclude>
<goals> <exclude>**/*.log</exclude>
<goal>${spotless.action}</goal> <exclude>CONTRIBUTING.md</exclude>
</goals> <exclude>README.md</exclude>
<phase>process-sources</phase> <exclude>**/codestyle/*</exclude>
</execution> <exclude>**/resources/META-INF/**</exclude>
</executions> <exclude>.github/**</exclude>
</plugin> <exclude>compiler/**</exclude>
</excludes>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>
</profile>
</profiles>
</project> </project>

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- <!--
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
@ -15,104 +14,53 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<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/maven-v4_0_0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<modelVersion>4.0.0</modelVersion> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent> <modelVersion>4.0.0</modelVersion>
<groupId>org.apache.dubbo</groupId> <parent>
<artifactId>dubbo-parent</artifactId> <groupId>org.apache.dubbo</groupId>
<version>${revision}</version> <artifactId>dubbo-parent</artifactId>
<relativePath>../pom.xml</relativePath> <version>${revision}</version>
</parent> <relativePath>../pom.xml</relativePath>
<artifactId>dubbo-cluster</artifactId> </parent>
<packaging>jar</packaging> <artifactId>dubbo-cluster</artifactId>
<name>${project.artifactId}</name> <packaging>jar</packaging>
<description>The cluster module of dubbo project</description> <name>${project.artifactId}</name>
<properties> <description>The cluster module of dubbo project</description>
<skip_maven_deploy>false</skip_maven_deploy> <properties>
<nashorn-core.version>15.4</nashorn-core.version> <skip_maven_deploy>false</skip_maven_deploy>
</properties> </properties>
<dependencies> <dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-api</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-rpc-injvm</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-hessian2</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-fastjson2</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-test-check</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-metrics-registry</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-metrics-default</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-integration-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<!--
https://github.com/openjdk/nashorn
Nashorn used to be part of the JDK until Java 14.
This project provides a standalone version of Nashorn suitable for use with Java 11 and later.
-->
<profile>
<id>nashorn-jdk11</id>
<activation>
<jdk>[11,)</jdk>
</activation>
<dependencies>
<dependency> <dependency>
<groupId>org.openjdk.nashorn</groupId> <groupId>org.apache.dubbo</groupId>
<artifactId>nashorn-core</artifactId> <artifactId>dubbo-rpc-api</artifactId>
<version>${nashorn-core.version}</version> <version>${project.parent.version}</version>
<scope>test</scope>
</dependency> </dependency>
</dependencies> <dependency>
</profile> <groupId>org.yaml</groupId>
</profiles> <artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-serialization-hessian2</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-test-check</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project> </project>

View File

@ -35,5 +35,8 @@ public interface AddressListener {
*/ */
List<URL> notify(List<URL> addresses, URL consumerUrl, Directory registryDirectory); List<URL> notify(List<URL> addresses, URL consumerUrl, Directory registryDirectory);
default void destroy(URL consumerUrl, Directory registryDirectory) {} default void destroy(URL consumerUrl, Directory registryDirectory) {
}
} }

View File

@ -17,7 +17,6 @@
package org.apache.dubbo.rpc.cluster; package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.ConcurrentHashMapUtils;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
@ -31,7 +30,7 @@ public abstract class CacheableRouterFactory implements RouterFactory {
@Override @Override
public Router getRouter(URL url) { public Router getRouter(URL url) {
return ConcurrentHashMapUtils.computeIfAbsent(routerMap, url.getServiceKey(), k -> createRouter(url)); return routerMap.computeIfAbsent(url.getServiceKey(), k -> createRouter(url));
} }
protected abstract Router createRouter(URL url); protected abstract Router createRouter(URL url);

View File

@ -55,8 +55,6 @@ public interface Cluster {
if (StringUtils.isEmpty(name)) { if (StringUtils.isEmpty(name)) {
name = Cluster.DEFAULT; name = Cluster.DEFAULT;
} }
return ScopeModelUtil.getApplicationModel(scopeModel) return ScopeModelUtil.getApplicationModel(scopeModel).getExtensionLoader(Cluster.class).getExtension(name, wrap);
.getExtensionLoader(Cluster.class)
.getExtension(name, wrap);
} }
} }

View File

@ -17,7 +17,6 @@
package org.apache.dubbo.rpc.cluster; package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.beans.factory.ScopeBeanFactory; import org.apache.dubbo.common.beans.factory.ScopeBeanFactory;
import org.apache.dubbo.rpc.AdaptiveMetrics;
import org.apache.dubbo.rpc.cluster.merger.MergerFactory; import org.apache.dubbo.rpc.cluster.merger.MergerFactory;
import org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher; import org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher;
import org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleManager; import org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleManager;
@ -39,7 +38,6 @@ public class ClusterScopeModelInitializer implements ScopeModelInitializer {
ScopeBeanFactory beanFactory = applicationModel.getBeanFactory(); ScopeBeanFactory beanFactory = applicationModel.getBeanFactory();
beanFactory.registerBean(MergerFactory.class); beanFactory.registerBean(MergerFactory.class);
beanFactory.registerBean(ClusterUtils.class); beanFactory.registerBean(ClusterUtils.class);
beanFactory.registerBean(AdaptiveMetrics.class);
} }
@Override @Override

View File

@ -51,6 +51,7 @@ public interface Configurator extends Comparable<Configurator> {
*/ */
URL configure(URL url); URL configure(URL url);
/** /**
* Convert override urls to map for use when re-refer. Send all rules every time, the urls will be reassembled and * Convert override urls to map for use when re-refer. Send all rules every time, the urls will be reassembled and
* calculated * calculated
@ -72,9 +73,7 @@ public interface Configurator extends Comparable<Configurator> {
return Optional.empty(); return Optional.empty();
} }
ConfiguratorFactory configuratorFactory = urls.get(0) ConfiguratorFactory configuratorFactory = urls.get(0).getOrDefaultApplicationModel().getExtensionLoader(ConfiguratorFactory.class)
.getOrDefaultApplicationModel()
.getExtensionLoader(ConfiguratorFactory.class)
.getAdaptiveExtension(); .getAdaptiveExtension();
List<Configurator> configurators = new ArrayList<>(urls.size()); List<Configurator> configurators = new ArrayList<>(urls.size());
@ -84,8 +83,7 @@ public interface Configurator extends Comparable<Configurator> {
break; break;
} }
Map<String, String> override = new HashMap<>(url.getParameters()); Map<String, String> override = new HashMap<>(url.getParameters());
// The anyhost parameter of override may be added automatically, it can't change the judgement of changing //The anyhost parameter of override may be added automatically, it can't change the judgement of changing url
// url
override.remove(ANYHOST_KEY); override.remove(ANYHOST_KEY);
if (CollectionUtils.isEmptyMap(override)) { if (CollectionUtils.isEmptyMap(override)) {
continue; continue;

View File

@ -17,7 +17,6 @@
package org.apache.dubbo.rpc.cluster; package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Adaptive; import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.common.extension.SPI;
@ -34,6 +33,7 @@ public interface ConfiguratorFactory {
* @param url - configurator url. * @param url - configurator url.
* @return configurator instance. * @return configurator instance.
*/ */
@Adaptive(CommonConstants.PROTOCOL_KEY) @Adaptive("protocol")
Configurator getConfigurator(URL url); Configurator getConfigurator(URL url);
} }

View File

@ -72,6 +72,8 @@ public interface Constants {
*/ */
boolean DEFAULT_CLUSTER_STICKY = false; boolean DEFAULT_CLUSTER_STICKY = false;
String ADDRESS_KEY = "address";
/** /**
* When this attribute appears in invocation's attachment, mock invoker will be used * When this attribute appears in invocation's attachment, mock invoker will be used
*/ */
@ -100,6 +102,7 @@ public interface Constants {
String OVERRIDE_PROVIDERS_KEY = "providerAddresses"; String OVERRIDE_PROVIDERS_KEY = "providerAddresses";
/** /**
* key for router type, for e.g., "script"/"file", corresponding to ScriptRouterFactory.NAME, FileRouterFactory.NAME * key for router type, for e.g., "script"/"file", corresponding to ScriptRouterFactory.NAME, FileRouterFactory.NAME
*/ */
@ -134,8 +137,4 @@ public interface Constants {
String SHORTEST_RESPONSE_SLIDE_PERIOD = "shortestResponseSlidePeriod"; String SHORTEST_RESPONSE_SLIDE_PERIOD = "shortestResponseSlidePeriod";
String SHOULD_FAIL_FAST_KEY = "dubbo.router.should-fail-fast"; String SHOULD_FAIL_FAST_KEY = "dubbo.router.should-fail-fast";
String RULE_VERSION_V27 = "v2.7";
String RULE_VERSION_V30 = "v3.0";
} }

View File

@ -46,4 +46,5 @@ public interface LoadBalance {
*/ */
@Adaptive("loadbalance") @Adaptive("loadbalance")
<T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException; <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
} }

View File

@ -22,4 +22,5 @@ import org.apache.dubbo.common.extension.SPI;
public interface Merger<T> { public interface Merger<T> {
T merge(T... items); T merge(T... items);
} }

View File

@ -33,9 +33,7 @@ public interface ProviderURLMergeProcessor {
*/ */
URL mergeUrl(URL remoteUrl, Map<String, String> localParametersMap); URL mergeUrl(URL remoteUrl, Map<String, String> localParametersMap);
default Map<String, String> mergeLocalParams(Map<String, String> localMap) { default Map<String, String> mergeLocalParams(Map<String, String> localMap) { return localMap; }
return localMap;
}
default boolean accept(URL providerUrl, Map<String, String> localParametersMap) { default boolean accept(URL providerUrl, Map<String, String> localParametersMap) {
return true; return true;

View File

@ -68,8 +68,8 @@ public interface Router extends Comparable<Router> {
* @return state with route result * @return state with route result
* @throws RpcException * @throws RpcException
*/ */
default <T> RouterResult<Invoker<T>> route( default <T> RouterResult<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation,
List<Invoker<T>> invokers, URL url, Invocation invocation, boolean needToPrintMessage) throws RpcException { boolean needToPrintMessage) throws RpcException {
return new RouterResult<>(route(invokers, url, invocation)); return new RouterResult<>(route(invokers, url, invocation));
} }
@ -80,7 +80,9 @@ public interface Router extends Comparable<Router> {
* @param invokers invoker list * @param invokers invoker list
* @param <T> invoker's type * @param <T> invoker's type
*/ */
default <T> void notify(List<Invoker<T>> invokers) {} default <T> void notify(List<Invoker<T>> invokers) {
}
/** /**
* To decide whether this router need to execute every time an RPC comes or should only execute when addresses or * To decide whether this router need to execute every time an RPC comes or should only execute when addresses or
@ -107,7 +109,7 @@ public interface Router extends Comparable<Router> {
int getPriority(); int getPriority();
default void stop() { default void stop() {
// do nothing by default //do nothing by default
} }
@Override @Override

View File

@ -17,23 +17,30 @@
package org.apache.dubbo.rpc.cluster; package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.config.ConfigurationUtils; import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.constants.LoggerCodeConstants; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.Holder;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.cluster.router.RouterResult;
import org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;
import org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher; import org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher;
import org.apache.dubbo.rpc.cluster.router.state.BitList; import org.apache.dubbo.rpc.cluster.router.state.BitList;
import org.apache.dubbo.rpc.cluster.router.state.StateRouter; import org.apache.dubbo.rpc.cluster.router.state.StateRouter;
import org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory; import org.apache.dubbo.rpc.cluster.router.state.StateRouterFactory;
import org.apache.dubbo.rpc.cluster.router.state.TailStateRouter;
import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ModuleModel;
import org.apache.dubbo.rpc.model.ScopeModelUtil; import org.apache.dubbo.rpc.model.ScopeModelUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.dubbo.rpc.cluster.Constants.ROUTER_KEY; import static org.apache.dubbo.rpc.cluster.Constants.ROUTER_KEY;
@ -42,205 +49,315 @@ import static org.apache.dubbo.rpc.cluster.Constants.ROUTER_KEY;
* Router chain * Router chain
*/ */
public class RouterChain<T> { public class RouterChain<T> {
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(RouterChain.class); private static final Logger logger = LoggerFactory.getLogger(RouterChain.class);
private volatile SingleRouterChain<T> mainChain; /**
private volatile SingleRouterChain<T> backupChain; * full list of addresses from registry, classified by method name.
private volatile SingleRouterChain<T> currentChain; */
private volatile BitList<Invoker<T>> invokers = BitList.emptyList();
/**
* containing all routers, reconstruct every time 'route://' urls change.
*/
private volatile List<Router> routers = Collections.emptyList();
/**
* Fixed router instances: ConfigConditionRouter, TagRouter, e.g.,
* the rule for each instance may change but the instance will never delete or recreate.
*/
private volatile List<Router> builtinRouters = Collections.emptyList();
private volatile StateRouter<T> headStateRouter;
private volatile List<StateRouter<T>> stateRouters;
/**
* Should continue route if current router's result is empty
*/
private final boolean shouldFailFast;
private final RouterSnapshotSwitcher routerSnapshotSwitcher;
@SuppressWarnings({"rawtypes", "unchecked"})
public static <T> RouterChain<T> buildChain(Class<T> interfaceClass, URL url) { public static <T> RouterChain<T> buildChain(Class<T> interfaceClass, URL url) {
SingleRouterChain<T> chain1 = buildSingleChain(interfaceClass, url);
SingleRouterChain<T> chain2 = buildSingleChain(interfaceClass, url);
return new RouterChain<>(new SingleRouterChain[] {chain1, chain2});
}
public static <T> SingleRouterChain<T> buildSingleChain(Class<T> interfaceClass, URL url) {
ModuleModel moduleModel = url.getOrDefaultModuleModel(); ModuleModel moduleModel = url.getOrDefaultModuleModel();
List<RouterFactory> extensionFactories = List<RouterFactory> extensionFactories = moduleModel.getExtensionLoader(RouterFactory.class)
moduleModel.getExtensionLoader(RouterFactory.class).getActivateExtension(url, ROUTER_KEY); .getActivateExtension(url, ROUTER_KEY);
List<Router> routers = extensionFactories.stream() List<Router> routers = extensionFactories.stream()
.map(factory -> factory.getRouter(url)) .map(factory -> factory.getRouter(url))
.sorted(Router::compareTo) .sorted(Router::compareTo)
.collect(Collectors.toList()); .collect(Collectors.toList());
List<StateRouter<T>> stateRouters = List<StateRouter<T>> stateRouters = moduleModel
moduleModel.getExtensionLoader(StateRouterFactory.class).getActivateExtension(url, ROUTER_KEY).stream() .getExtensionLoader(StateRouterFactory.class)
.map(factory -> factory.getRouter(interfaceClass, url)) .getActivateExtension(url, ROUTER_KEY)
.collect(Collectors.toList()); .stream()
.map(factory -> factory.getRouter(interfaceClass, url))
.collect(Collectors.toList());
boolean shouldFailFast = Boolean.parseBoolean(
ConfigurationUtils.getProperty(moduleModel, Constants.SHOULD_FAIL_FAST_KEY, "true"));
RouterSnapshotSwitcher routerSnapshotSwitcher = boolean shouldFailFast = Boolean.parseBoolean(ConfigurationUtils.getProperty(moduleModel, Constants.SHOULD_FAIL_FAST_KEY, "true"));
ScopeModelUtil.getFrameworkModel(moduleModel).getBeanFactory().getBean(RouterSnapshotSwitcher.class);
return new SingleRouterChain<>(routers, stateRouters, shouldFailFast, routerSnapshotSwitcher); RouterSnapshotSwitcher routerSnapshotSwitcher = ScopeModelUtil.getFrameworkModel(moduleModel).getBeanFactory().getBean(RouterSnapshotSwitcher.class);
return new RouterChain<>(routers, stateRouters, shouldFailFast, routerSnapshotSwitcher);
} }
public RouterChain(SingleRouterChain<T>[] chains) { public RouterChain(List<Router> routers, List<StateRouter<T>> stateRouters, boolean shouldFailFast, RouterSnapshotSwitcher routerSnapshotSwitcher) {
if (chains.length != 2) { initWithRouters(routers);
throw new IllegalArgumentException("chains' size should be 2.");
initWithStateRouters(stateRouters);
this.shouldFailFast = shouldFailFast;
this.routerSnapshotSwitcher = routerSnapshotSwitcher;
}
private void initWithStateRouters(List<StateRouter<T>> stateRouters) {
StateRouter<T> stateRouter = TailStateRouter.getInstance();
for (int i = stateRouters.size() - 1; i >= 0; i--) {
StateRouter<T> nextStateRouter = stateRouters.get(i);
nextStateRouter.setNextRouter(stateRouter);
stateRouter = nextStateRouter;
} }
this.mainChain = chains[0]; this.headStateRouter = stateRouter;
this.backupChain = chains[1]; this.stateRouters = Collections.unmodifiableList(stateRouters);
this.currentChain = this.mainChain;
}
private final AtomicReference<BitList<Invoker<T>>> notifyingInvokers = new AtomicReference<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public ReadWriteLock getLock() {
return lock;
}
public SingleRouterChain<T> getSingleChain(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
// If current is in:
// 1. `setInvokers` is in progress
// 2. Most of the invocation should use backup chain => currentChain == backupChain
// 3. Main chain has been update success => notifyingInvokers.get() != null
// If `availableInvokers` is created from origin invokers => use backup chain
// If `availableInvokers` is created from newly invokers => use main chain
BitList<Invoker<T>> notifying = notifyingInvokers.get();
if (notifying != null
&& currentChain == backupChain
&& availableInvokers.getOriginList() == notifying.getOriginList()) {
return mainChain;
}
return currentChain;
} }
/** /**
* @deprecated use {@link RouterChain#getSingleChain(URL, BitList, Invocation)} and {@link SingleRouterChain#route(URL, BitList, Invocation)} instead * the resident routers must being initialized before address notification.
* only for ut
*/ */
@Deprecated public void initWithRouters(List<Router> builtinRouters) {
this.builtinRouters = builtinRouters;
this.routers = new LinkedList<>(builtinRouters);
}
/**
* If we use route:// protocol in version before 2.7.0, each URL will generate a Router instance, so we should
* keep the routers up to date, that is, each time router URLs changes, we should update the routers list, only
* keep the builtinRouters which are available all the time and the latest notified routers which are generated
* from URLs.
*
* @param routers routers from 'router://' rules in 2.6.x or before.
*/
public void addRouters(List<Router> routers) {
List<Router> newRouters = new LinkedList<>();
newRouters.addAll(builtinRouters);
newRouters.addAll(routers);
CollectionUtils.sort(newRouters);
this.routers = newRouters;
}
public List<Router> getRouters() {
return routers;
}
public StateRouter<T> getHeadStateRouter() {
return headStateRouter;
}
public List<Invoker<T>> route(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) { public List<Invoker<T>> route(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
return getSingleChain(url, availableInvokers, invocation).route(url, availableInvokers, invocation); if (RpcContext.getServiceContext().isNeedPrintRouterSnapshot()) {
return routeAndPrint(url, availableInvokers, invocation);
} else {
return simpleRoute(url, availableInvokers, invocation);
}
}
public List<Invoker<T>> routeAndPrint(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
RouterSnapshotNode<T> snapshot = buildRouterSnapshot(url, availableInvokers, invocation);
logRouterSnapshot(url, invocation, snapshot);
return snapshot.getChainOutputInvokers();
}
public List<Invoker<T>> simpleRoute(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
BitList<Invoker<T>> resultInvokers = availableInvokers.clone();
// 1. route state router
resultInvokers = headStateRouter.route(resultInvokers, url, invocation, false, null);
if (resultInvokers.isEmpty() && (shouldFailFast || routers.isEmpty())) {
printRouterSnapshot(url, availableInvokers, invocation);
return BitList.emptyList();
}
if (routers.isEmpty()) {
return resultInvokers;
}
List<Invoker<T>> commonRouterResult = resultInvokers.cloneToArrayList();
// 2. route common router
for (Router router : routers) {
// Copy resultInvokers to a arrayList. BitList not support
RouterResult<Invoker<T>> routeResult = router.route(commonRouterResult, url, invocation, false);
commonRouterResult = routeResult.getResult();
if (CollectionUtils.isEmpty(commonRouterResult) && shouldFailFast) {
printRouterSnapshot(url, availableInvokers, invocation);
return BitList.emptyList();
}
// stop continue routing
if (!routeResult.isNeedContinueRoute()) {
return commonRouterResult;
}
}
if (commonRouterResult.isEmpty()) {
printRouterSnapshot(url, availableInvokers, invocation);
return BitList.emptyList();
}
return commonRouterResult;
}
/**
* store each router's input and output, log out if empty
*/
private void printRouterSnapshot(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
if (logger.isWarnEnabled()) {
logRouterSnapshot(url, invocation, buildRouterSnapshot(url, availableInvokers, invocation));
}
}
/**
* Build each router's result
*/
public RouterSnapshotNode<T> buildRouterSnapshot(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
BitList<Invoker<T>> resultInvokers = availableInvokers.clone();
RouterSnapshotNode<T> parentNode = new RouterSnapshotNode<T>("Parent", resultInvokers.clone());
parentNode.setNodeOutputInvokers(resultInvokers.clone());
// 1. route state router
Holder<RouterSnapshotNode<T>> nodeHolder = new Holder<>();
nodeHolder.set(parentNode);
resultInvokers = headStateRouter.route(resultInvokers, url, invocation, true, nodeHolder);
// result is empty, log out
if (routers.isEmpty() || (resultInvokers.isEmpty() && shouldFailFast)) {
parentNode.setChainOutputInvokers(resultInvokers.clone());
return parentNode;
}
RouterSnapshotNode<T> commonRouterNode = new RouterSnapshotNode<T>("CommonRouter", resultInvokers.clone());
parentNode.appendNode(commonRouterNode);
List<Invoker<T>> commonRouterResult = resultInvokers;
// 2. route common router
for (Router router : routers) {
// Copy resultInvokers to a arrayList. BitList not support
List<Invoker<T>> inputInvokers = new ArrayList<>(commonRouterResult);
RouterSnapshotNode<T> currentNode = new RouterSnapshotNode<T>(router.getClass().getSimpleName(), inputInvokers);
// append to router node chain
commonRouterNode.appendNode(currentNode);
commonRouterNode = currentNode;
RouterResult<Invoker<T>> routeStateResult = router.route(inputInvokers, url, invocation, true);
List<Invoker<T>> routeResult = routeStateResult.getResult();
String routerMessage = routeStateResult.getMessage();
currentNode.setNodeOutputInvokers(routeResult);
currentNode.setRouterMessage(routerMessage);
commonRouterResult = routeResult;
// result is empty, log out
if (CollectionUtils.isEmpty(routeResult) && shouldFailFast) {
break;
}
if (!routeStateResult.isNeedContinueRoute()) {
break;
}
}
commonRouterNode.setChainOutputInvokers(commonRouterNode.getNodeOutputInvokers());
// 3. set router chain output reverse
RouterSnapshotNode<T> currentNode = commonRouterNode;
while (currentNode != null){
RouterSnapshotNode<T> parent = currentNode.getParentNode();
if (parent != null) {
// common router only has one child invoke
parent.setChainOutputInvokers(currentNode.getChainOutputInvokers());
}
currentNode = parent;
}
return parentNode;
}
private void logRouterSnapshot(URL url, Invocation invocation, RouterSnapshotNode<T> snapshotNode) {
if (snapshotNode.getChainOutputInvokers() == null ||
snapshotNode.getChainOutputInvokers().isEmpty()) {
if (logger.isWarnEnabled()) {
String message = "No provider available after route for the service " + url.getServiceKey()
+ " from registry " + url.getAddress()
+ " on the consumer " + NetUtils.getLocalHost()
+ " using the dubbo version " + Version.getVersion() + ". Router snapshot is below: \n" + snapshotNode.toString();
if (routerSnapshotSwitcher.isEnable()) {
routerSnapshotSwitcher.setSnapshot(message);
}
logger.warn(message);
}
} else {
if (logger.isInfoEnabled()) {
String message = "Router snapshot service " + url.getServiceKey()
+ " from registry " + url.getAddress()
+ " on the consumer " + NetUtils.getLocalHost()
+ " using the dubbo version " + Version.getVersion() + " is below: \n" + snapshotNode.toString();
if (routerSnapshotSwitcher.isEnable()) {
routerSnapshotSwitcher.setSnapshot(message);
}
logger.info(message);
}
}
} }
/** /**
* Notify router chain of the initial addresses from registry at the first time. * Notify router chain of the initial addresses from registry at the first time.
* Notify whenever addresses in registry change. * Notify whenever addresses in registry change.
*/ */
public synchronized void setInvokers(BitList<Invoker<T>> invokers, Runnable switchAction) { public void setInvokers(BitList<Invoker<T>> invokers) {
try { this.invokers = (invokers == null ? BitList.emptyList() : invokers);
// Lock to prevent directory continue list routers.forEach(router -> router.notify(this.invokers));
lock.writeLock().lock(); stateRouters.forEach(router -> router.notify(this.invokers));
// Switch to back up chain. Will update main chain first.
currentChain = backupChain;
} finally {
// Release lock to minimize the impact for each newly created invocations as much as possible.
// Should not release lock until main chain update finished. Or this may cause long hang.
lock.writeLock().unlock();
}
// Refresh main chain.
// No one can request to use main chain. `currentChain` is backup chain. `route` method cannot access main
// chain.
try {
// Lock main chain to wait all invocation end
// To wait until no one is using main chain.
mainChain.getLock().writeLock().lock();
// refresh
mainChain.setInvokers(invokers);
} catch (Throwable t) {
logger.error(LoggerCodeConstants.INTERNAL_ERROR, "", "", "Error occurred when refreshing router chain.", t);
throw t;
} finally {
// Unlock main chain
mainChain.getLock().writeLock().unlock();
}
// Set the reference of newly invokers to temp variable.
// Reason: The next step will switch the invokers reference in directory, so we should check the
// `availableInvokers`
// argument when `route`. If the current invocation use newly invokers, we should use main chain to
// route, and
// this can prevent use newly invokers to route backup chain, which can only route origin invokers now.
notifyingInvokers.set(invokers);
// Switch the invokers reference in directory.
// Cannot switch before update main chain or after backup chain update success. Or that will cause state
// inconsistent.
switchAction.run();
try {
// Lock to prevent directory continue list
// The invokers reference in directory now should be the newly one and should always use the newly one once
// lock released.
lock.writeLock().lock();
// Switch to main chain. Will update backup chain later.
currentChain = mainChain;
// Clean up temp variable.
// `availableInvokers` check is useless now, because `route` method will no longer receive any
// `availableInvokers` related
// with the origin invokers. The getter of invokers reference in directory is locked now, and will return
// newly invokers
// once lock released.
notifyingInvokers.set(null);
} finally {
// Release lock to minimize the impact for each newly created invocations as much as possible.
// Will use newly invokers and main chain now.
lock.writeLock().unlock();
}
// Refresh main chain.
// No one can request to use main chain. `currentChain` is main chain. `route` method cannot access backup
// chain.
try {
// Lock main chain to wait all invocation end
backupChain.getLock().writeLock().lock();
// refresh
backupChain.setInvokers(invokers);
} catch (Throwable t) {
logger.error(LoggerCodeConstants.INTERNAL_ERROR, "", "", "Error occurred when refreshing router chain.", t);
throw t;
} finally {
// Unlock backup chain
backupChain.getLock().writeLock().unlock();
}
} }
public synchronized void destroy() { /**
// 1. destroy another * for uts only
backupChain.destroy(); */
@Deprecated
// 2. switch public void setHeadStateRouter(StateRouter<T> headStateRouter) {
lock.writeLock().lock(); this.headStateRouter = headStateRouter;
currentChain = backupChain;
lock.writeLock().unlock();
// 4. destroy
mainChain.destroy();
}
public void addRouters(List<Router> routers) {
mainChain.addRouters(routers);
backupChain.addRouters(routers);
}
public SingleRouterChain<T> getCurrentChain() {
return currentChain;
}
public List<Router> getRouters() {
return currentChain.getRouters();
}
public StateRouter<T> getHeadStateRouter() {
return currentChain.getHeadStateRouter();
} }
/**
* for uts only
*/
@Deprecated @Deprecated
public List<StateRouter<T>> getStateRouters() { public List<StateRouter<T>> getStateRouters() {
return currentChain.getStateRouters(); return stateRouters;
}
public void destroy() {
invokers = BitList.emptyList();
for (Router router : routers) {
try {
router.stop();
} catch (Exception e) {
logger.error("Error trying to stop router " + router.getClass(), e);
}
}
routers = Collections.emptyList();
builtinRouters = Collections.emptyList();
for (StateRouter<T> router : stateRouters) {
try {
router.stop();
} catch (Exception e) {
logger.error("Error trying to stop stateRouter " + router.getClass(), e);
}
}
stateRouters = Collections.emptyList();
headStateRouter = TailStateRouter.getInstance();
} }
} }

View File

@ -17,7 +17,6 @@
package org.apache.dubbo.rpc.cluster; package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Adaptive; import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.common.extension.SPI;
@ -43,6 +42,6 @@ public interface RouterFactory {
* @param url url * @param url url
* @return router instance * @return router instance
*/ */
@Adaptive(CommonConstants.PROTOCOL_KEY) @Adaptive("protocol")
Router getRouter(URL url); Router getRouter(URL url);
} }

View File

@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster; package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
@ -25,4 +26,5 @@ import java.util.List;
public interface RuleConverter { public interface RuleConverter {
List<URL> convert(URL subscribeUrl, Object source); List<URL> convert(URL subscribeUrl, Object source);
} }

View File

@ -1,371 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.Holder;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.cluster.router.RouterResult;
import org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;
import org.apache.dubbo.rpc.cluster.router.RouterSnapshotSwitcher;
import org.apache.dubbo.rpc.cluster.router.state.BitList;
import org.apache.dubbo.rpc.cluster.router.state.StateRouter;
import org.apache.dubbo.rpc.cluster.router.state.TailStateRouter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_STOP;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_NO_VALID_PROVIDER;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;
/**
* Router chain
*/
public class SingleRouterChain<T> {
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SingleRouterChain.class);
/**
* full list of addresses from registry, classified by method name.
*/
private volatile BitList<Invoker<T>> invokers = BitList.emptyList();
/**
* containing all routers, reconstruct every time 'route://' urls change.
*/
private volatile List<Router> routers = Collections.emptyList();
/**
* Fixed router instances: ConfigConditionRouter, TagRouter, e.g.,
* the rule for each instance may change but the instance will never delete or recreate.
*/
private volatile List<Router> builtinRouters = Collections.emptyList();
private volatile StateRouter<T> headStateRouter;
private volatile List<StateRouter<T>> stateRouters;
/**
* Should continue route if current router's result is empty
*/
private final boolean shouldFailFast;
private final RouterSnapshotSwitcher routerSnapshotSwitcher;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public SingleRouterChain(
List<Router> routers,
List<StateRouter<T>> stateRouters,
boolean shouldFailFast,
RouterSnapshotSwitcher routerSnapshotSwitcher) {
initWithRouters(routers);
initWithStateRouters(stateRouters);
this.shouldFailFast = shouldFailFast;
this.routerSnapshotSwitcher = routerSnapshotSwitcher;
}
private void initWithStateRouters(List<StateRouter<T>> stateRouters) {
StateRouter<T> stateRouter = TailStateRouter.getInstance();
for (int i = stateRouters.size() - 1; i >= 0; i--) {
StateRouter<T> nextStateRouter = stateRouters.get(i);
nextStateRouter.setNextRouter(stateRouter);
stateRouter = nextStateRouter;
}
this.headStateRouter = stateRouter;
this.stateRouters = Collections.unmodifiableList(stateRouters);
}
/**
* the resident routers must being initialized before address notification.
* only for ut
*/
public void initWithRouters(List<Router> builtinRouters) {
this.builtinRouters = builtinRouters;
this.routers = new LinkedList<>(builtinRouters);
}
/**
* If we use route:// protocol in version before 2.7.0, each URL will generate a Router instance, so we should
* keep the routers up to date, that is, each time router URLs changes, we should update the routers list, only
* keep the builtinRouters which are available all the time and the latest notified routers which are generated
* from URLs.
*
* @param routers routers from 'router://' rules in 2.6.x or before.
*/
public void addRouters(List<Router> routers) {
List<Router> newRouters = new LinkedList<>();
newRouters.addAll(builtinRouters);
newRouters.addAll(routers);
CollectionUtils.sort(newRouters);
this.routers = newRouters;
}
public List<Router> getRouters() {
return routers;
}
public StateRouter<T> getHeadStateRouter() {
return headStateRouter;
}
public List<Invoker<T>> route(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
if (invokers.getOriginList() != availableInvokers.getOriginList()) {
logger.error(
INTERNAL_ERROR,
"",
"Router's invoker size: " + invokers.getOriginList().size() + " Invocation's invoker size: "
+ availableInvokers.getOriginList().size(),
"Reject to route, because the invokers has changed.");
throw new IllegalStateException("reject to route, because the invokers has changed.");
}
if (RpcContext.getServiceContext().isNeedPrintRouterSnapshot()) {
return routeAndPrint(url, availableInvokers, invocation);
} else {
return simpleRoute(url, availableInvokers, invocation);
}
}
public List<Invoker<T>> routeAndPrint(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
RouterSnapshotNode<T> snapshot = buildRouterSnapshot(url, availableInvokers, invocation);
logRouterSnapshot(url, invocation, snapshot);
return snapshot.getChainOutputInvokers();
}
public List<Invoker<T>> simpleRoute(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
BitList<Invoker<T>> resultInvokers = availableInvokers.clone();
// 1. route state router
resultInvokers = headStateRouter.route(resultInvokers, url, invocation, false, null);
if (resultInvokers.isEmpty() && (shouldFailFast || routers.isEmpty())) {
printRouterSnapshot(url, availableInvokers, invocation);
return BitList.emptyList();
}
if (routers.isEmpty()) {
return resultInvokers;
}
List<Invoker<T>> commonRouterResult = resultInvokers.cloneToArrayList();
// 2. route common router
for (Router router : routers) {
// Copy resultInvokers to a arrayList. BitList not support
RouterResult<Invoker<T>> routeResult = router.route(commonRouterResult, url, invocation, false);
commonRouterResult = routeResult.getResult();
if (CollectionUtils.isEmpty(commonRouterResult) && shouldFailFast) {
printRouterSnapshot(url, availableInvokers, invocation);
return BitList.emptyList();
}
// stop continue routing
if (!routeResult.isNeedContinueRoute()) {
return commonRouterResult;
}
}
if (commonRouterResult.isEmpty()) {
printRouterSnapshot(url, availableInvokers, invocation);
return BitList.emptyList();
}
return commonRouterResult;
}
/**
* store each router's input and output, log out if empty
*/
private void printRouterSnapshot(URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
if (logger.isWarnEnabled()) {
logRouterSnapshot(url, invocation, buildRouterSnapshot(url, availableInvokers, invocation));
}
}
/**
* Build each router's result
*/
public RouterSnapshotNode<T> buildRouterSnapshot(
URL url, BitList<Invoker<T>> availableInvokers, Invocation invocation) {
BitList<Invoker<T>> resultInvokers = availableInvokers.clone();
RouterSnapshotNode<T> parentNode = new RouterSnapshotNode<>("Parent", resultInvokers.clone());
parentNode.setNodeOutputInvokers(resultInvokers.clone());
// 1. route state router
Holder<RouterSnapshotNode<T>> nodeHolder = new Holder<>();
nodeHolder.set(parentNode);
resultInvokers = headStateRouter.route(resultInvokers, url, invocation, true, nodeHolder);
// result is empty, log out
if (routers.isEmpty() || (resultInvokers.isEmpty() && shouldFailFast)) {
parentNode.setChainOutputInvokers(resultInvokers.clone());
return parentNode;
}
RouterSnapshotNode<T> commonRouterNode = new RouterSnapshotNode<>("CommonRouter", resultInvokers.clone());
parentNode.appendNode(commonRouterNode);
List<Invoker<T>> commonRouterResult = resultInvokers;
// 2. route common router
for (Router router : routers) {
// Copy resultInvokers to a arrayList. BitList not support
List<Invoker<T>> inputInvokers = new ArrayList<>(commonRouterResult);
RouterSnapshotNode<T> currentNode =
new RouterSnapshotNode<>(router.getClass().getSimpleName(), inputInvokers);
// append to router node chain
commonRouterNode.appendNode(currentNode);
commonRouterNode = currentNode;
RouterResult<Invoker<T>> routeStateResult = router.route(inputInvokers, url, invocation, true);
List<Invoker<T>> routeResult = routeStateResult.getResult();
String routerMessage = routeStateResult.getMessage();
currentNode.setNodeOutputInvokers(routeResult);
currentNode.setRouterMessage(routerMessage);
commonRouterResult = routeResult;
// result is empty, log out
if (CollectionUtils.isEmpty(routeResult) && shouldFailFast) {
break;
}
if (!routeStateResult.isNeedContinueRoute()) {
break;
}
}
commonRouterNode.setChainOutputInvokers(commonRouterNode.getNodeOutputInvokers());
// 3. set router chain output reverse
RouterSnapshotNode<T> currentNode = commonRouterNode;
while (currentNode != null) {
RouterSnapshotNode<T> parent = currentNode.getParentNode();
if (parent != null) {
// common router only has one child invoke
parent.setChainOutputInvokers(currentNode.getChainOutputInvokers());
}
currentNode = parent;
}
return parentNode;
}
private void logRouterSnapshot(URL url, Invocation invocation, RouterSnapshotNode<T> snapshotNode) {
if (snapshotNode.getChainOutputInvokers() == null
|| snapshotNode.getChainOutputInvokers().isEmpty()) {
if (logger.isWarnEnabled()) {
String message = "No provider available after route for the service " + url.getServiceKey()
+ " from registry " + url.getAddress()
+ " on the consumer " + NetUtils.getLocalHost()
+ " using the dubbo version " + Version.getVersion() + ". Router snapshot is below: \n"
+ snapshotNode.toString();
if (routerSnapshotSwitcher.isEnable()) {
routerSnapshotSwitcher.setSnapshot(message);
}
logger.warn(
CLUSTER_NO_VALID_PROVIDER, "No provider available after route for the service", "", message);
}
} else {
if (logger.isInfoEnabled()) {
String message = "Router snapshot service " + url.getServiceKey()
+ " from registry " + url.getAddress()
+ " on the consumer " + NetUtils.getLocalHost()
+ " using the dubbo version " + Version.getVersion() + " is below: \n"
+ snapshotNode.toString();
if (routerSnapshotSwitcher.isEnable()) {
routerSnapshotSwitcher.setSnapshot(message);
}
logger.info(message);
}
}
}
/**
* Notify router chain of the initial addresses from registry at the first time.
* Notify whenever addresses in registry change.
*/
public void setInvokers(BitList<Invoker<T>> invokers) {
this.invokers = (invokers == null ? BitList.emptyList() : invokers);
routers.forEach(router -> router.notify(this.invokers));
stateRouters.forEach(router -> router.notify(this.invokers));
}
/**
* for uts only
*/
@Deprecated
public void setHeadStateRouter(StateRouter<T> headStateRouter) {
this.headStateRouter = headStateRouter;
}
/**
* for uts only
*/
@Deprecated
public List<StateRouter<T>> getStateRouters() {
return stateRouters;
}
public ReadWriteLock getLock() {
return lock;
}
public void destroy() {
invokers = BitList.emptyList();
for (Router router : routers) {
try {
router.stop();
} catch (Exception e) {
logger.error(
CLUSTER_FAILED_STOP,
"route stop failed",
"",
"Error trying to stop router " + router.getClass(),
e);
}
}
routers = Collections.emptyList();
builtinRouters = Collections.emptyList();
for (StateRouter<T> router : stateRouters) {
try {
router.stop();
} catch (Exception e) {
logger.error(
CLUSTER_FAILED_STOP,
"StateRouter stop failed",
"",
"Error trying to stop StateRouter " + router.getClass(),
e);
}
}
stateRouters = Collections.emptyList();
headStateRouter = TailStateRouter.getInstance();
}
}

View File

@ -17,14 +17,10 @@
package org.apache.dubbo.rpc.cluster.configurator; package org.apache.dubbo.rpc.cluster.configurator;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.remoting.Constants; import org.apache.dubbo.remoting.Constants;
import org.apache.dubbo.rpc.cluster.Configurator; import org.apache.dubbo.rpc.cluster.Configurator;
import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConditionMatch;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
@ -45,14 +41,12 @@ import static org.apache.dubbo.common.constants.RegistryConstants.COMPATIBLE_CON
import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.CONFIG_VERSION_KEY; import static org.apache.dubbo.rpc.cluster.Constants.CONFIG_VERSION_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY; import static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.RULE_VERSION_V30;
import static org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig.MATCH_CONDITION;
/** /**
* AbstractConfigurator * AbstractConfigurator
*/ */
public abstract class AbstractConfigurator implements Configurator { public abstract class AbstractConfigurator implements Configurator {
private static final Logger logger = LoggerFactory.getLogger(AbstractConfigurator.class);
private static final String TILDE = "~"; private static final String TILDE = "~";
private final URL configuratorUrl; private final URL configuratorUrl;
@ -72,21 +66,20 @@ public abstract class AbstractConfigurator implements Configurator {
@Override @Override
public URL configure(URL url) { public URL configure(URL url) {
// If override url is not enabled or is invalid, just return. // If override url is not enabled or is invalid, just return.
if (!configuratorUrl.getParameter(ENABLED_KEY, true) if (!configuratorUrl.getParameter(ENABLED_KEY, true) || configuratorUrl.getHost() == null || url == null || url.getHost() == null) {
|| configuratorUrl.getHost() == null
|| url == null
|| url.getHost() == null) {
logger.info("Cannot apply configurator rule, the rule is disabled or is invalid: \n" + configuratorUrl);
return url; return url;
} }
/*
* This if branch is created since 2.7.0.
*/
String apiVersion = configuratorUrl.getParameter(CONFIG_VERSION_KEY); String apiVersion = configuratorUrl.getParameter(CONFIG_VERSION_KEY);
if (StringUtils.isNotEmpty(apiVersion)) { // v2.7 or above if (StringUtils.isNotEmpty(apiVersion)) {
String currentSide = url.getSide(); String currentSide = url.getSide();
String configuratorSide = configuratorUrl.getSide(); String configuratorSide = configuratorUrl.getSide();
if (currentSide.equals(configuratorSide) && CONSUMER.equals(configuratorSide)) { if (currentSide.equals(configuratorSide) && CONSUMER.equals(configuratorSide) && 0 == configuratorUrl.getPort()) {
url = configureIfMatch(NetUtils.getLocalHost(), url); url = configureIfMatch(NetUtils.getLocalHost(), url);
} else if (currentSide.equals(configuratorSide) && PROVIDER.equals(configuratorSide)) { } else if (currentSide.equals(configuratorSide) && PROVIDER.equals(configuratorSide) &&
url.getPort() == configuratorUrl.getPort()) {
url = configureIfMatch(url.getHost(), url); url = configureIfMatch(url.getHost(), url);
} }
} }
@ -101,9 +94,7 @@ public abstract class AbstractConfigurator implements Configurator {
@Deprecated @Deprecated
private URL configureDeprecated(URL url) { private URL configureDeprecated(URL url) {
// If override url has port, means it is a provider address. We want to control a specific provider with this // If override url has port, means it is a provider address. We want to control a specific provider with this override url, it may take effect on the specific provider instance or on consumers holding this provider instance.
// override url, it may take effect on the specific provider instance or on consumers holding this provider
// instance.
if (configuratorUrl.getPort() != 0) { if (configuratorUrl.getPort() != 0) {
if (url.getPort() == configuratorUrl.getPort()) { if (url.getPort() == configuratorUrl.getPort()) {
return configureIfMatch(url.getHost(), url); return configureIfMatch(url.getHost(), url);
@ -127,120 +118,53 @@ public abstract class AbstractConfigurator implements Configurator {
private URL configureIfMatch(String host, URL url) { private URL configureIfMatch(String host, URL url) {
if (ANYHOST_VALUE.equals(configuratorUrl.getHost()) || host.equals(configuratorUrl.getHost())) { if (ANYHOST_VALUE.equals(configuratorUrl.getHost()) || host.equals(configuratorUrl.getHost())) {
if (isV27ConditionMatchOrUnset(url)) { // TODO, to support wildcards
Set<String> conditionKeys = genConditionKeys(); String providers = configuratorUrl.getParameter(OVERRIDE_PROVIDERS_KEY);
String apiVersion = configuratorUrl.getParameter(CONFIG_VERSION_KEY); if (StringUtils.isEmpty(providers) || providers.contains(url.getAddress()) || providers.contains(ANYHOST_VALUE)) {
if (apiVersion != null && apiVersion.startsWith(RULE_VERSION_V30)) { String configApplication = configuratorUrl.getApplication(configuratorUrl.getUsername());
ConditionMatch matcher = (ConditionMatch) configuratorUrl.getAttribute(MATCH_CONDITION); String currentApplication = url.getApplication(url.getUsername());
if (matcher != null) { if (configApplication == null || ANY_VALUE.equals(configApplication)
if (matcher.isMatch(host, url)) { || configApplication.equals(currentApplication)) {
return doConfigure(url, configuratorUrl.removeParameters(conditionKeys)); Set<String> conditionKeys = new HashSet<String>();
} else { conditionKeys.add(CATEGORY_KEY);
logger.debug("Cannot apply configurator rule, param mismatch, current params are " + url conditionKeys.add(Constants.CHECK_KEY);
+ ", params in rule is " + matcher); conditionKeys.add(DYNAMIC_KEY);
conditionKeys.add(ENABLED_KEY);
conditionKeys.add(GROUP_KEY);
conditionKeys.add(VERSION_KEY);
conditionKeys.add(APPLICATION_KEY);
conditionKeys.add(SIDE_KEY);
conditionKeys.add(CONFIG_VERSION_KEY);
conditionKeys.add(COMPATIBLE_CONFIG_KEY);
conditionKeys.add(INTERFACES);
for (Map.Entry<String, String> entry : configuratorUrl.getParameters().entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
boolean startWithTilde = startWithTilde(key);
if (startWithTilde || APPLICATION_KEY.equals(key) || SIDE_KEY.equals(key)) {
if (startWithTilde) {
conditionKeys.add(key);
}
if (value != null && !ANY_VALUE.equals(value)
&& !value.equals(url.getParameter(startWithTilde ? key.substring(1) : key))) {
return url;
}
} }
} else {
return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));
} }
} else if (isDeprecatedConditionMatch(conditionKeys, url)) {
return doConfigure(url, configuratorUrl.removeParameters(conditionKeys)); return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));
} }
} }
} else {
logger.debug("Cannot apply configurator rule, host mismatch, current host is " + host + ", host in rule is "
+ configuratorUrl.getHost());
} }
return url; return url;
} }
/**
* Check if v2.7 configurator rule is set and can be matched.
*
* @param url the configurator rule url
* @return true if v2.7 configurator rule is not set or the rule can be matched.
*/
private boolean isV27ConditionMatchOrUnset(URL url) {
String providers = configuratorUrl.getParameter(OVERRIDE_PROVIDERS_KEY);
if (StringUtils.isNotEmpty(providers)) {
boolean match = false;
String[] providerAddresses = providers.split(CommonConstants.COMMA_SEPARATOR);
for (String address : providerAddresses) {
if (address.equals(url.getAddress())
|| address.equals(ANYHOST_VALUE)
|| address.equals(ANYHOST_VALUE + CommonConstants.GROUP_CHAR_SEPARATOR + ANY_VALUE)
|| address.equals(ANYHOST_VALUE + CommonConstants.GROUP_CHAR_SEPARATOR + url.getPort())
|| address.equals(url.getHost())) {
match = true;
}
}
if (!match) {
logger.debug("Cannot apply configurator rule, provider address mismatch, current address "
+ url.getAddress() + ", address in rule is " + providers);
return false;
}
}
String configApplication = configuratorUrl.getApplication(configuratorUrl.getUsername());
String currentApplication = url.getApplication(url.getUsername());
if (configApplication != null
&& !ANY_VALUE.equals(configApplication)
&& !configApplication.equals(currentApplication)) {
logger.debug("Cannot apply configurator rule, application name mismatch, current application is "
+ currentApplication + ", application in rule is " + configApplication);
return false;
}
String configServiceKey = configuratorUrl.getServiceKey();
String currentServiceKey = url.getServiceKey();
if (!ANY_VALUE.equals(configServiceKey) && !configServiceKey.equals(currentServiceKey)) {
logger.debug("Cannot apply configurator rule, service mismatch, current service is " + currentServiceKey
+ ", service in rule is " + configServiceKey);
return false;
}
return true;
}
private boolean isDeprecatedConditionMatch(Set<String> conditionKeys, URL url) {
boolean result = true;
for (Map.Entry<String, String> entry : configuratorUrl.getParameters().entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
boolean startWithTilde = startWithTilde(key);
if (startWithTilde || APPLICATION_KEY.equals(key) || SIDE_KEY.equals(key)) {
if (startWithTilde) {
conditionKeys.add(key);
}
if (value != null
&& !ANY_VALUE.equals(value)
&& !value.equals(url.getParameter(startWithTilde ? key.substring(1) : key))) {
result = false;
break;
}
}
}
return result;
}
private Set<String> genConditionKeys() {
Set<String> conditionKeys = new HashSet<>();
conditionKeys.add(CATEGORY_KEY);
conditionKeys.add(Constants.CHECK_KEY);
conditionKeys.add(DYNAMIC_KEY);
conditionKeys.add(ENABLED_KEY);
conditionKeys.add(GROUP_KEY);
conditionKeys.add(VERSION_KEY);
conditionKeys.add(APPLICATION_KEY);
conditionKeys.add(SIDE_KEY);
conditionKeys.add(CONFIG_VERSION_KEY);
conditionKeys.add(COMPATIBLE_CONFIG_KEY);
conditionKeys.add(INTERFACES);
return conditionKeys;
}
private boolean startWithTilde(String key) { private boolean startWithTilde(String key) {
return StringUtils.isNotEmpty(key) && key.startsWith(TILDE); if (StringUtils.isNotEmpty(key) && key.startsWith(TILDE)) {
return true;
}
return false;
} }
protected abstract URL doConfigure(URL currentUrl, URL configUrl); protected abstract URL doConfigure(URL currentUrl, URL configUrl);
} }

View File

@ -32,4 +32,5 @@ public class AbsentConfigurator extends AbstractConfigurator {
public URL doConfigure(URL currentUrl, URL configUrl) { public URL doConfigure(URL currentUrl, URL configUrl) {
return currentUrl.addParametersIfAbsent(configUrl.getParameters()); return currentUrl.addParametersIfAbsent(configUrl.getParameters());
} }
} }

View File

@ -30,4 +30,5 @@ public class AbsentConfiguratorFactory implements ConfiguratorFactory {
public Configurator getConfigurator(URL url) { public Configurator getConfigurator(URL url) {
return new AbsentConfigurator(url); return new AbsentConfigurator(url);
} }
} }

View File

@ -17,15 +17,12 @@
package org.apache.dubbo.rpc.cluster.configurator.override; package org.apache.dubbo.rpc.cluster.configurator.override;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator; import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator;
/** /**
* OverrideConfigurator * OverrideConfigurator
*/ */
public class OverrideConfigurator extends AbstractConfigurator { public class OverrideConfigurator extends AbstractConfigurator {
public static final Logger logger = LoggerFactory.getLogger(OverrideConfigurator.class);
public OverrideConfigurator(URL url) { public OverrideConfigurator(URL url) {
super(url); super(url);
@ -33,7 +30,7 @@ public class OverrideConfigurator extends AbstractConfigurator {
@Override @Override
public URL doConfigure(URL currentUrl, URL configUrl) { public URL doConfigure(URL currentUrl, URL configUrl) {
logger.info("Start overriding url " + currentUrl + " with override url " + configUrl);
return currentUrl.addParameters(configUrl.getParameters()); return currentUrl.addParameters(configUrl.getParameters());
} }
} }

View File

@ -30,4 +30,5 @@ public class OverrideConfiguratorFactory implements ConfiguratorFactory {
public Configurator getConfigurator(URL url) { public Configurator getConfigurator(URL url) {
return new OverrideConfigurator(url); return new OverrideConfigurator(url);
} }
} }

View File

@ -23,20 +23,17 @@ import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfigItem; import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfigItem;
import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig; import org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE; import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
import static org.apache.dubbo.common.constants.RegistryConstants.APP_DYNAMIC_CONFIGURATORS_CATEGORY; import static org.apache.dubbo.common.constants.RegistryConstants.APP_DYNAMIC_CONFIGURATORS_CATEGORY;
import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_CONFIGURATORS_CATEGORY; import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_CONFIGURATORS_CATEGORY;
import static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY; import static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY;
import static org.apache.dubbo.rpc.cluster.configurator.parser.model.ConfiguratorConfig.MATCH_CONDITION;
/** /**
* Config parser * Config parser
@ -62,14 +59,13 @@ public class ConfigParser {
// service scope by default. // service scope by default.
items.forEach(item -> urls.addAll(serviceItemToUrls(item, configuratorConfig))); items.forEach(item -> urls.addAll(serviceItemToUrls(item, configuratorConfig)));
} }
return urls; return urls;
} }
private static List<URL> parseJsonArray(String rawConfig) { private static List<URL> parseJsonArray(String rawConfig) {
List<URL> urls = new ArrayList<>(); List<URL> urls = new ArrayList<>();
try { try {
List<String> list = JsonUtils.toJavaList(rawConfig, String.class); List<String> list = JsonUtils.getJson().toJavaList(rawConfig, String.class);
if (!CollectionUtils.isEmpty(list)) { if (!CollectionUtils.isEmpty(list)) {
list.forEach(u -> urls.add(URL.valueOf(u))); list.forEach(u -> urls.add(URL.valueOf(u)));
} }
@ -80,7 +76,7 @@ public class ConfigParser {
} }
private static ConfiguratorConfig parseObject(String rawConfig) { private static ConfiguratorConfig parseObject(String rawConfig) {
Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions())); Yaml yaml = new Yaml(new SafeConstructor());
Map<String, Object> map = yaml.load(rawConfig); Map<String, Object> map = yaml.load(rawConfig);
return ConfiguratorConfig.parseFromMap(map); return ConfiguratorConfig.parseFromMap(map);
} }
@ -104,15 +100,10 @@ public class ConfigParser {
if (CollectionUtils.isNotEmpty(apps)) { if (CollectionUtils.isNotEmpty(apps)) {
apps.forEach(app -> { apps.forEach(app -> {
StringBuilder tmpUrlBuilder = new StringBuilder(urlBuilder); StringBuilder tmpUrlBuilder = new StringBuilder(urlBuilder);
urls.add(appendMatchCondition( urls.add(URL.valueOf(tmpUrlBuilder.append("&application=").append(app).toString()));
URL.valueOf(tmpUrlBuilder
.append("&application=")
.append(app)
.toString()),
item));
}); });
} else { } else {
urls.add(appendMatchCondition(URL.valueOf(urlBuilder.toString()), item)); urls.add(URL.valueOf(urlBuilder.toString()));
} }
}); });
@ -144,7 +135,7 @@ public class ConfigParser {
tmpUrlBuilder.append("&category=").append(APP_DYNAMIC_CONFIGURATORS_CATEGORY); tmpUrlBuilder.append("&category=").append(APP_DYNAMIC_CONFIGURATORS_CATEGORY);
tmpUrlBuilder.append("&configVersion=").append(config.getConfigVersion()); tmpUrlBuilder.append("&configVersion=").append(config.getConfigVersion());
urls.add(appendMatchCondition(URL.valueOf(tmpUrlBuilder.toString()), item)); urls.add(URL.valueOf(tmpUrlBuilder.toString()));
} }
} }
return urls; return urls;
@ -160,8 +151,8 @@ public class ConfigParser {
} }
Map<String, String> parameters = item.getParameters(); Map<String, String> parameters = item.getParameters();
if (CollectionUtils.isEmptyMap(parameters)) { if (CollectionUtils.isEmptyMap(parameters)) {
throw new IllegalStateException("Invalid configurator rule, please specify at least one parameter " throw new IllegalStateException("Invalid configurator rule, please specify at least one parameter " +
+ "you want to change in the rule."); "you want to change in the rule.");
} }
parameters.forEach((k, v) -> { parameters.forEach((k, v) -> {
@ -176,11 +167,6 @@ public class ConfigParser {
sb.append(OVERRIDE_PROVIDERS_KEY); sb.append(OVERRIDE_PROVIDERS_KEY);
sb.append('='); sb.append('=');
sb.append(CollectionUtils.join(item.getProviderAddresses(), ",")); sb.append(CollectionUtils.join(item.getProviderAddresses(), ","));
} else if (PROVIDER.equals(item.getSide())) {
sb.append('&');
sb.append(OVERRIDE_PROVIDERS_KEY);
sb.append('=');
sb.append(CollectionUtils.join(parseAddresses(item), ","));
} }
return sb.toString(); return sb.toString();
@ -232,11 +218,4 @@ public class ConfigParser {
} }
return addresses; return addresses;
} }
private static URL appendMatchCondition(URL url, ConfigItem item) {
if (item.getMatch() != null) {
url = url.putAttribute(MATCH_CONDITION, item.getMatch());
}
return url;
}
} }

View File

@ -1,111 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.rpc.cluster.configurator.parser.model;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.AddressMatch;
import org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.ListStringMatch;
import java.util.List;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
public class ConditionMatch {
private AddressMatch address;
private AddressMatch providerAddress;
private ListStringMatch service;
private ListStringMatch app;
private List<ParamMatch> param;
public AddressMatch getAddress() {
return address;
}
public void setAddress(AddressMatch address) {
this.address = address;
}
public AddressMatch getProviderAddress() {
return providerAddress;
}
public void setProviderAddress(AddressMatch providerAddress) {
this.providerAddress = providerAddress;
}
public ListStringMatch getService() {
return service;
}
public void setService(ListStringMatch service) {
this.service = service;
}
public ListStringMatch getApp() {
return app;
}
public void setApp(ListStringMatch app) {
this.app = app;
}
public List<ParamMatch> getParam() {
return param;
}
public void setParam(List<ParamMatch> param) {
this.param = param;
}
public boolean isMatch(String host, URL url) {
if (getAddress() != null && !getAddress().isMatch(host)) {
return false;
}
if (getProviderAddress() != null && !getProviderAddress().isMatch(url.getAddress())) {
return false;
}
if (getService() != null && !getService().isMatch(url.getServiceKey())) {
return false;
}
if (getApp() != null && !getApp().isMatch(url.getParameter(APPLICATION_KEY))) {
return false;
}
if (getParam() != null) {
for (ParamMatch match : param) {
if (!match.isMatch(url)) {
return false;
}
}
}
return true;
}
@Override
public String toString() {
return "ConditionMatch{" + "address='"
+ address + '\'' + "providerAddress='"
+ providerAddress + '\'' + ", service='"
+ service + '\'' + ", app='"
+ app + '\'' + ", param='"
+ param + '\'' + '}';
}
}

View File

@ -16,22 +16,14 @@
*/ */
package org.apache.dubbo.rpc.cluster.configurator.parser.model; package org.apache.dubbo.rpc.cluster.configurator.parser.model;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.PojoUtils;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_RECEIVE_RULE;
/** /**
* *
*/ */
public class ConfigItem { public class ConfigItem {
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(ConfigItem.class);
public static final String GENERAL_TYPE = "general"; public static final String GENERAL_TYPE = "general";
public static final String WEIGHT_TYPE = "weight"; public static final String WEIGHT_TYPE = "weight";
public static final String BALANCING_TYPE = "balancing"; public static final String BALANCING_TYPE = "balancing";
@ -43,7 +35,6 @@ public class ConfigItem {
public static final String SERVICES_KEY = "services"; public static final String SERVICES_KEY = "services";
public static final String APPLICATIONS_KEY = "applications"; public static final String APPLICATIONS_KEY = "applications";
public static final String PARAMETERS_KEY = "parameters"; public static final String PARAMETERS_KEY = "parameters";
public static final String MATCH_KEY = "match";
public static final String SIDE_KEY = "side"; public static final String SIDE_KEY = "side";
private String type; private String type;
@ -53,7 +44,6 @@ public class ConfigItem {
private List<String> services; private List<String> services;
private List<String> applications; private List<String> applications;
private Map<String, String> parameters; private Map<String, String> parameters;
private ConditionMatch match;
private String side; private String side;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -68,49 +58,33 @@ public class ConfigItem {
Object addresses = map.get(ADDRESSES_KEY); Object addresses = map.get(ADDRESSES_KEY);
if (addresses != null && List.class.isAssignableFrom(addresses.getClass())) { if (addresses != null && List.class.isAssignableFrom(addresses.getClass())) {
configItem.setAddresses( configItem.setAddresses(((List<Object>) addresses).stream()
((List<Object>) addresses).stream().map(String::valueOf).collect(Collectors.toList())); .map(String::valueOf).collect(Collectors.toList()));
} }
Object providerAddresses = map.get(PROVIDER_ADDRESSES_KEY); Object providerAddresses = map.get(PROVIDER_ADDRESSES_KEY);
if (providerAddresses != null && List.class.isAssignableFrom(providerAddresses.getClass())) { if (providerAddresses != null && List.class.isAssignableFrom(providerAddresses.getClass())) {
configItem.setProviderAddresses(((List<Object>) providerAddresses) configItem.setProviderAddresses(((List<Object>) providerAddresses).stream()
.stream().map(String::valueOf).collect(Collectors.toList())); .map(String::valueOf).collect(Collectors.toList()));
} }
Object services = map.get(SERVICES_KEY); Object services = map.get(SERVICES_KEY);
if (services != null && List.class.isAssignableFrom(services.getClass())) { if (services != null && List.class.isAssignableFrom(services.getClass())) {
configItem.setServices( configItem.setServices(((List<Object>) services).stream()
((List<Object>) services).stream().map(String::valueOf).collect(Collectors.toList())); .map(String::valueOf).collect(Collectors.toList()));
} }
Object applications = map.get(APPLICATIONS_KEY); Object applications = map.get(APPLICATIONS_KEY);
if (applications != null && List.class.isAssignableFrom(applications.getClass())) { if (applications != null && List.class.isAssignableFrom(applications.getClass())) {
configItem.setApplications( configItem.setApplications(((List<Object>) applications).stream()
((List<Object>) applications).stream().map(String::valueOf).collect(Collectors.toList())); .map(String::valueOf).collect(Collectors.toList()));
} }
Object parameters = map.get(PARAMETERS_KEY); Object parameters = map.get(PARAMETERS_KEY);
if (parameters != null && Map.class.isAssignableFrom(parameters.getClass())) { if (parameters != null && Map.class.isAssignableFrom(parameters.getClass())) {
configItem.setParameters(((Map<String, Object>) parameters) configItem.setParameters(((Map<String, Object>) parameters).entrySet()
.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue() .stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().toString())));
.toString())));
} }
try {
Object match = map.get(MATCH_KEY);
if (match != null && Map.class.isAssignableFrom(match.getClass())) {
configItem.setMatch(PojoUtils.mapToPojo((Map<String, Object>) match, ConditionMatch.class));
}
} catch (Throwable t) {
logger.error(
CLUSTER_FAILED_RECEIVE_RULE,
" Failed to parse dynamic configuration rule",
String.valueOf(map.get(MATCH_KEY)),
"Error occurred when parsing rule component.",
t);
}
configItem.setSide((String) map.get(SIDE_KEY)); configItem.setSide((String) map.get(SIDE_KEY));
return configItem; return configItem;
} }
@ -178,12 +152,4 @@ public class ConfigItem {
public void setSide(String side) { public void setSide(String side) {
this.side = side; this.side = side;
} }
public ConditionMatch getMatch() {
return match;
}
public void setMatch(ConditionMatch match) {
this.match = match;
}
} }

View File

@ -24,7 +24,6 @@ import java.util.stream.Collectors;
* *
*/ */
public class ConfiguratorConfig { public class ConfiguratorConfig {
public static final String MATCH_CONDITION = "MATCH_CONDITION";
public static final String SCOPE_SERVICE = "service"; public static final String SCOPE_SERVICE = "service";
public static final String SCOPE_APPLICATION = "application"; public static final String SCOPE_APPLICATION = "application";
public static final String CONFIG_VERSION_KEY = "configVersion"; public static final String CONFIG_VERSION_KEY = "configVersion";
@ -52,8 +51,8 @@ public class ConfiguratorConfig {
Object configs = map.get(CONFIGS_KEY); Object configs = map.get(CONFIGS_KEY);
if (configs != null && List.class.isAssignableFrom(configs.getClass())) { if (configs != null && List.class.isAssignableFrom(configs.getClass())) {
configuratorConfig.setConfigs(((List<Map<String, Object>>) configs) configuratorConfig.setConfigs(((List<Map<String, Object>>) configs).stream()
.stream().map(ConfigItem::parseFromMap).collect(Collectors.toList())); .map(ConfigItem::parseFromMap).collect(Collectors.toList()));
} }
return configuratorConfig; return configuratorConfig;

View File

@ -1,55 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.rpc.cluster.configurator.parser.model;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.cluster.router.mesh.rule.virtualservice.match.StringMatch;
public class ParamMatch {
private String key;
private StringMatch value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public StringMatch getValue() {
return value;
}
public void setValue(StringMatch value) {
this.value = value;
}
public boolean isMatch(URL url) {
if (key == null || value == null) {
return false;
}
String input = url.getParameter(key);
return value.isMatch(input);
}
@Override
public String toString() {
return "ParamMatch{" + "key='" + key + '\'' + ", value='" + value + '\'' + '}';
}
}

View File

@ -20,17 +20,12 @@ import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.Version; import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.config.Configuration; import org.apache.dubbo.common.config.Configuration;
import org.apache.dubbo.common.config.ConfigurationUtils; import org.apache.dubbo.common.config.ConfigurationUtils;
import org.apache.dubbo.common.constants.LoggerCodeConstants; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;
import org.apache.dubbo.common.utils.ConcurrentHashSet; import org.apache.dubbo.common.utils.ConcurrentHashSet;
import org.apache.dubbo.common.utils.LockUtils;
import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.model.key.MetricsKey;
import org.apache.dubbo.metrics.registry.event.RegistryEvent;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcContext;
@ -38,7 +33,6 @@ import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.Router; import org.apache.dubbo.rpc.cluster.Router;
import org.apache.dubbo.rpc.cluster.RouterChain; import org.apache.dubbo.rpc.cluster.RouterChain;
import org.apache.dubbo.rpc.cluster.SingleRouterChain;
import org.apache.dubbo.rpc.cluster.router.state.BitList; import org.apache.dubbo.rpc.cluster.router.state.BitList;
import org.apache.dubbo.rpc.cluster.support.ClusterUtils; import org.apache.dubbo.rpc.cluster.support.ClusterUtils;
import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.ApplicationModel;
@ -46,7 +40,6 @@ import org.apache.dubbo.rpc.model.ApplicationModel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -57,9 +50,6 @@ import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER; import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_RECONNECT_TASK_PERIOD; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_RECONNECT_TASK_PERIOD;
@ -71,7 +61,6 @@ import static org.apache.dubbo.common.constants.CommonConstants.PROTOCOL_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.RECONNECT_TASK_PERIOD; import static org.apache.dubbo.common.constants.CommonConstants.RECONNECT_TASK_PERIOD;
import static org.apache.dubbo.common.constants.CommonConstants.RECONNECT_TASK_TRY_COUNT; import static org.apache.dubbo.common.constants.CommonConstants.RECONNECT_TASK_TRY_COUNT;
import static org.apache.dubbo.common.constants.CommonConstants.REGISTER_IP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.REGISTER_IP_KEY;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_NO_VALID_PROVIDER;
import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty;
import static org.apache.dubbo.rpc.cluster.Constants.CONSUMER_URL_KEY; import static org.apache.dubbo.rpc.cluster.Constants.CONSUMER_URL_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY; import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
@ -82,7 +71,7 @@ import static org.apache.dubbo.rpc.cluster.Constants.REFER_KEY;
public abstract class AbstractDirectory<T> implements Directory<T> { public abstract class AbstractDirectory<T> implements Directory<T> {
// logger // logger
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractDirectory.class); private static final Logger logger = LoggerFactory.getLogger(AbstractDirectory.class);
private final URL url; private final URL url;
@ -125,8 +114,6 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
private volatile ScheduledFuture<?> connectivityCheckFuture; private volatile ScheduledFuture<?> connectivityCheckFuture;
private final ReentrantLock invokerRefreshLock = new ReentrantLock();
/** /**
* The max count of invokers for each reconnect task select to try to reconnect. * The max count of invokers for each reconnect task select to try to reconnect.
*/ */
@ -137,8 +124,6 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
*/ */
private final int reconnectTaskPeriod; private final int reconnectTaskPeriod;
private ApplicationModel applicationModel;
public AbstractDirectory(URL url) { public AbstractDirectory(URL url) {
this(url, null, false); this(url, null, false);
} }
@ -164,21 +149,19 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
} }
// remove some local only parameters // remove some local only parameters
applicationModel = url.getOrDefaultApplicationModel(); ApplicationModel applicationModel = url.getOrDefaultApplicationModel();
this.queryMap = this.queryMap = applicationModel.getBeanFactory().getBean(ClusterUtils.class).mergeLocalParams(queryMap);
applicationModel.getBeanFactory().getBean(ClusterUtils.class).mergeLocalParams(queryMap);
if (consumerUrl == null) { if (consumerUrl == null) {
String host = String host = isNotEmpty(queryMap.get(REGISTER_IP_KEY)) ? queryMap.get(REGISTER_IP_KEY) : this.url.getHost();
isNotEmpty(queryMap.get(REGISTER_IP_KEY)) ? queryMap.get(REGISTER_IP_KEY) : this.url.getHost();
String path = isNotEmpty(queryMap.get(PATH_KEY)) ? queryMap.get(PATH_KEY) : queryMap.get(INTERFACE_KEY); String path = isNotEmpty(queryMap.get(PATH_KEY)) ? queryMap.get(PATH_KEY) : queryMap.get(INTERFACE_KEY);
String consumedProtocol = isNotEmpty(queryMap.get(PROTOCOL_KEY)) ? queryMap.get(PROTOCOL_KEY) : CONSUMER; String consumedProtocol = isNotEmpty(queryMap.get(PROTOCOL_KEY)) ? queryMap.get(PROTOCOL_KEY) : CONSUMER;
URL consumerUrlFrom = this.url URL consumerUrlFrom = this.url
.setHost(host) .setHost(host)
.setPort(0) .setPort(0)
.setProtocol(consumedProtocol) .setProtocol(consumedProtocol)
.setPath(path); .setPath(path);
if (isUrlFromRegistry) { if (isUrlFromRegistry) {
// reserve parameters if url is already a consumer url // reserve parameters if url is already a consumer url
consumerUrlFrom = consumerUrlFrom.clearParameters(); consumerUrlFrom = consumerUrlFrom.clearParameters();
@ -186,11 +169,8 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
this.consumerUrl = consumerUrlFrom.addParameters(queryMap); this.consumerUrl = consumerUrlFrom.addParameters(queryMap);
} }
this.connectivityExecutor = applicationModel this.connectivityExecutor = applicationModel.getFrameworkModel().getBeanFactory()
.getFrameworkModel() .getBean(FrameworkExecutorRepository.class).getConnectivityScheduledExecutor();
.getBeanFactory()
.getBean(FrameworkExecutorRepository.class)
.getConnectivityScheduledExecutor();
Configuration configuration = ConfigurationUtils.getGlobalConfiguration(url.getOrDefaultModuleModel()); Configuration configuration = ConfigurationUtils.getGlobalConfiguration(url.getOrDefaultModuleModel());
this.reconnectTaskTryCount = configuration.getInt(RECONNECT_TASK_TRY_COUNT, DEFAULT_RECONNECT_TASK_TRY_COUNT); this.reconnectTaskTryCount = configuration.getInt(RECONNECT_TASK_TRY_COUNT, DEFAULT_RECONNECT_TASK_TRY_COUNT);
this.reconnectTaskPeriod = configuration.getInt(RECONNECT_TASK_PERIOD, DEFAULT_RECONNECT_TASK_PERIOD); this.reconnectTaskPeriod = configuration.getInt(RECONNECT_TASK_PERIOD, DEFAULT_RECONNECT_TASK_PERIOD);
@ -200,56 +180,28 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
@Override @Override
public List<Invoker<T>> list(Invocation invocation) throws RpcException { public List<Invoker<T>> list(Invocation invocation) throws RpcException {
if (destroyed) { if (destroyed) {
throw new RpcException( throw new RpcException("Directory of type " + this.getClass().getSimpleName() + " already destroyed for service " + getConsumerUrl().getServiceKey() + " from registry " + getUrl());
"Directory of type " + this.getClass().getSimpleName() + " already destroyed for service "
+ getConsumerUrl().getServiceKey() + " from registry " + getUrl());
} }
BitList<Invoker<T>> availableInvokers; BitList<Invoker<T>> availableInvokers;
SingleRouterChain<T> singleChain = null; // use clone to avoid being modified at doList().
try { if (invokersInitialized) {
try { availableInvokers = validInvokers.clone();
if (routerChain != null) { } else {
routerChain.getLock().readLock().lock(); availableInvokers = invokers.clone();
}
// use clone to avoid being modified at doList().
if (invokersInitialized) {
availableInvokers = validInvokers.clone();
} else {
availableInvokers = invokers.clone();
}
if (routerChain != null) {
singleChain = routerChain.getSingleChain(getConsumerUrl(), availableInvokers, invocation);
singleChain.getLock().readLock().lock();
}
} finally {
if (routerChain != null) {
routerChain.getLock().readLock().unlock();
}
}
List<Invoker<T>> routedResult = doList(singleChain, availableInvokers, invocation);
if (routedResult.isEmpty()) {
// 2-2 - No provider available.
logger.warn(
CLUSTER_NO_VALID_PROVIDER,
"provider server or registry center crashed",
"",
"No provider available after connectivity filter for the service "
+ getConsumerUrl().getServiceKey()
+ " All routed invokers' size: " + routedResult.size()
+ " from registry " + this
+ " on the consumer " + NetUtils.getLocalHost()
+ " using the dubbo version " + Version.getVersion() + ".");
}
return Collections.unmodifiableList(routedResult);
} finally {
if (singleChain != null) {
singleChain.getLock().readLock().unlock();
}
} }
List<Invoker<T>> routedResult = doList(availableInvokers, invocation);
if (routedResult.isEmpty()) {
logger.warn("No provider available after connectivity filter for the service " + getConsumerUrl().getServiceKey()
+ " All validInvokers' size: " + validInvokers.size()
+ " All routed invokers' size: " + routedResult.size()
+ " All invokers' size: " + invokers.size()
+ " from registry " + getUrl().getAddress()
+ " on the consumer " + NetUtils.getLocalHost()
+ " using the dubbo version " + Version.getVersion() + ".");
}
return Collections.unmodifiableList(routedResult);
} }
@Override @Override
@ -298,109 +250,70 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
@Override @Override
public void addInvalidateInvoker(Invoker<T> invoker) { public void addInvalidateInvoker(Invoker<T> invoker) {
LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { // 1. remove this invoker from validInvokers list, this invoker will not be listed in the next time
// 1. remove this invoker from validInvokers list, this invoker will not be listed in the next time if (removeValidInvoker(invoker)) {
if (removeValidInvoker(invoker)) { // 2. add this invoker to reconnect list
// 2. add this invoker to reconnect list invokersToReconnect.add(invoker);
invokersToReconnect.add(invoker); // 3. try start check connectivity task
// 3. try start check connectivity task checkConnectivity();
checkConnectivity(); }
logger.info("The invoker " + invoker.getUrl()
+ " has been added to invalidate list due to connectivity problem. "
+ "Will trying to reconnect to it in the background.");
}
});
} }
public void checkConnectivity() { public void checkConnectivity() {
// try to submit task, to ensure there is only one task at most for each directory // try to submit task, to ensure there is only one task at most for each directory
if (checkConnectivityPermit.tryAcquire()) { if (checkConnectivityPermit.tryAcquire()) {
this.connectivityCheckFuture = connectivityExecutor.schedule( this.connectivityCheckFuture = connectivityExecutor.schedule(() -> {
() -> { try {
try { if (isDestroyed()) {
if (isDestroyed()) { return;
return; }
RpcContext.getServiceContext().setConsumerUrl(getConsumerUrl());
List<Invoker<T>> needDeleteList = new ArrayList<>();
List<Invoker<T>> invokersToTry = new ArrayList<>();
// 1. pick invokers from invokersToReconnect
// limit max reconnectTaskTryCount, prevent this task hang up all the connectivityExecutor for long time
if (invokersToReconnect.size() < reconnectTaskTryCount) {
invokersToTry.addAll(invokersToReconnect);
} else {
for (int i = 0; i < reconnectTaskTryCount; i++) {
Invoker<T> tInvoker = invokersToReconnect.get(ThreadLocalRandom.current().nextInt(invokersToReconnect.size()));
if (!invokersToTry.contains(tInvoker)) {
// ignore if is selected, invokersToTry's size is always smaller than reconnectTaskTryCount + 1
invokersToTry.add(tInvoker);
} }
RpcContext.getServiceContext().setConsumerUrl(getConsumerUrl());
List<Invoker<T>> needDeleteList = new ArrayList<>();
List<Invoker<T>> invokersToTry = new ArrayList<>();
// 1. pick invokers from invokersToReconnect
// limit max reconnectTaskTryCount, prevent this task hang up all the connectivityExecutor
// for long time
LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> {
if (invokersToReconnect.size() < reconnectTaskTryCount) {
invokersToTry.addAll(invokersToReconnect);
} else {
for (int i = 0; i < reconnectTaskTryCount; i++) {
Invoker<T> tInvoker = invokersToReconnect.get(
ThreadLocalRandom.current().nextInt(invokersToReconnect.size()));
if (!invokersToTry.contains(tInvoker)) {
// ignore if is selected, invokersToTry's size is always smaller than
// reconnectTaskTryCount + 1
invokersToTry.add(tInvoker);
}
}
}
});
// 2. try to check the invoker's status
for (Invoker<T> invoker : invokersToTry) {
AtomicBoolean invokerExist = new AtomicBoolean(false);
LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> {
invokerExist.set(invokers.contains(invoker));
});
// Should not lock here, `invoker.isAvailable` may need some time to check
if (invokerExist.get()) {
if (invoker.isAvailable()) {
needDeleteList.add(invoker);
}
} else {
needDeleteList.add(invoker);
}
}
// 3. recover valid invoker
LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> {
for (Invoker<T> tInvoker : needDeleteList) {
if (invokers.contains(tInvoker)) {
addValidInvoker(tInvoker);
logger.info("Recover service address: " + tInvoker.getUrl()
+ " from invalid list.");
} else {
logger.info(
"The invoker " + tInvoker.getUrl()
+ " has been removed from invokers list. Will remove it in reconnect list.");
}
invokersToReconnect.remove(tInvoker);
}
});
} catch (Throwable t) {
logger.error(
LoggerCodeConstants.INTERNAL_ERROR,
"",
"",
"Error occurred when check connectivity. ",
t);
} finally {
checkConnectivityPermit.release();
} }
}
// 4. submit new task if it has more to recover // 2. try to check the invoker's status
LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { for (Invoker<T> invoker : invokersToTry) {
if (!invokersToReconnect.isEmpty()) { if (invokers.contains(invoker)) {
checkConnectivity(); if (invoker.isAvailable()) {
needDeleteList.add(invoker);
} }
}); } else {
MetricsEventBus.publish(RegistryEvent.refreshDirectoryEvent( needDeleteList.add(invoker);
applicationModel, getSummary(), getDirectoryMeta())); }
}, }
reconnectTaskPeriod,
TimeUnit.MILLISECONDS); // 3. recover valid invoker
for (Invoker<T> tInvoker : needDeleteList) {
if (invokers.contains(tInvoker)) {
addValidInvoker(tInvoker);
logger.info("Recover service address: " + tInvoker.getUrl() + " from invalid list.");
}
invokersToReconnect.remove(tInvoker);
}
} finally {
checkConnectivityPermit.release();
}
// 4. submit new task if it has more to recover
if (!invokersToReconnect.isEmpty()) {
checkConnectivity();
}
}, reconnectTaskPeriod, TimeUnit.MILLISECONDS);
} }
MetricsEventBus.publish(
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
} }
/** /**
@ -411,20 +324,12 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
* 4. all the invokers disappeared from total invokers should be removed in the disabled invokers list * 4. all the invokers disappeared from total invokers should be removed in the disabled invokers list
*/ */
public void refreshInvoker() { public void refreshInvoker() {
LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { if (invokersInitialized) {
if (invokersInitialized) { refreshInvokerInternal();
refreshInvokerInternal(); }
}
});
MetricsEventBus.publish(
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
} }
protected Map<String, String> getDirectoryMeta() { private synchronized void refreshInvokerInternal() {
return Collections.emptyMap();
}
private void refreshInvokerInternal() {
BitList<Invoker<T>> copiedInvokers = invokers.clone(); BitList<Invoker<T>> copiedInvokers = invokers.clone();
refreshInvokers(copiedInvokers, invokersToReconnect); refreshInvokers(copiedInvokers, invokersToReconnect);
refreshInvokers(copiedInvokers, disabledInvokers); refreshInvokers(copiedInvokers, disabledInvokers);
@ -445,49 +350,22 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
@Override @Override
public void addDisabledInvoker(Invoker<T> invoker) { public void addDisabledInvoker(Invoker<T> invoker) {
LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { if (invokers.contains(invoker)) {
if (invokers.contains(invoker)) { disabledInvokers.add(invoker);
disabledInvokers.add(invoker); removeValidInvoker(invoker);
removeValidInvoker(invoker); logger.info("Disable service address: " + invoker.getUrl() + ".");
logger.info("Disable service address: " + invoker.getUrl() + "."); }
}
});
MetricsEventBus.publish(
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
} }
@Override @Override
public void recoverDisabledInvoker(Invoker<T> invoker) { public void recoverDisabledInvoker(Invoker<T> invoker) {
LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { if (disabledInvokers.remove(invoker)) {
if (disabledInvokers.remove(invoker)) { try {
try { addValidInvoker(invoker);
addValidInvoker(invoker); logger.info("Recover service address: " + invoker.getUrl() + " from disabled list.");
logger.info("Recover service address: " + invoker.getUrl() + " from disabled list."); } catch (Throwable ignore) {
} catch (Throwable ignore) {
}
} }
});
MetricsEventBus.publish(
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
}
protected final void refreshRouter(BitList<Invoker<T>> newlyInvokers, Runnable switchAction) {
try {
routerChain.setInvokers(newlyInvokers.clone(), switchAction);
} catch (Throwable t) {
logger.error(
LoggerCodeConstants.INTERNAL_ERROR,
"",
"",
"Error occurred when refreshing router chain. " + "The addresses from notification: "
+ newlyInvokers.stream()
.map(Invoker::getUrl)
.map(URL::getAddress)
.collect(Collectors.joining(", ")),
t);
throw t;
} }
} }
@ -526,98 +404,30 @@ public abstract class AbstractDirectory<T> implements Directory<T> {
} }
protected void setInvokers(BitList<Invoker<T>> invokers) { protected void setInvokers(BitList<Invoker<T>> invokers) {
LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { this.invokers = invokers;
this.invokers = invokers; refreshInvokerInternal();
refreshInvokerInternal(); this.invokersInitialized = true;
this.invokersInitialized = true;
});
MetricsEventBus.publish(
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
} }
protected void destroyInvokers() { protected void destroyInvokers() {
// set empty instead of clearing to support concurrent access. // set empty instead of clearing to support concurrent access.
LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { this.invokers = BitList.emptyList();
this.invokers = BitList.emptyList(); this.validInvokers = BitList.emptyList();
this.validInvokers = BitList.emptyList(); this.invokersInitialized = false;
this.invokersInitialized = false;
});
} }
private boolean addValidInvoker(Invoker<T> invoker) { private boolean addValidInvoker(Invoker<T> invoker) {
AtomicBoolean result = new AtomicBoolean(false); synchronized (this.validInvokers) {
LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { return this.validInvokers.add(invoker);
result.set(this.validInvokers.add(invoker)); }
});
MetricsEventBus.publish(
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
return result.get();
} }
private boolean removeValidInvoker(Invoker<T> invoker) { private boolean removeValidInvoker(Invoker<T> invoker) {
AtomicBoolean result = new AtomicBoolean(false); synchronized (this.validInvokers) {
LockUtils.safeLock(invokerRefreshLock, LockUtils.DEFAULT_TIMEOUT, () -> { return this.validInvokers.remove(invoker);
result.set(this.validInvokers.remove(invoker));
});
MetricsEventBus.publish(
RegistryEvent.refreshDirectoryEvent(applicationModel, getSummary(), getDirectoryMeta()));
return result.get();
}
protected abstract List<Invoker<T>> doList(
SingleRouterChain<T> singleRouterChain, BitList<Invoker<T>> invokers, Invocation invocation)
throws RpcException;
protected String joinValidInvokerAddresses() {
BitList<Invoker<T>> validInvokers = getValidInvokers().clone();
if (validInvokers.isEmpty()) {
return "empty";
} }
return validInvokers.stream()
.limit(5)
.map(Invoker::getUrl)
.map(URL::getAddress)
.collect(Collectors.joining(","));
} }
private Map<MetricsKey, Map<String, Integer>> getSummary() { protected abstract List<Invoker<T>> doList(BitList<Invoker<T>> invokers, Invocation invocation) throws RpcException;
Map<MetricsKey, Map<String, Integer>> summaryMap = new HashMap<>();
summaryMap.put(MetricsKey.DIRECTORY_METRIC_NUM_VALID, groupByServiceKey(getValidInvokers()));
summaryMap.put(MetricsKey.DIRECTORY_METRIC_NUM_DISABLE, groupByServiceKey(getDisabledInvokers()));
summaryMap.put(MetricsKey.DIRECTORY_METRIC_NUM_TO_RECONNECT, groupByServiceKey(getInvokersToReconnect()));
summaryMap.put(MetricsKey.DIRECTORY_METRIC_NUM_ALL, groupByServiceKey(getInvokers()));
return summaryMap;
}
private Map<String, Integer> groupByServiceKey(Collection<Invoker<T>> invokers) {
return Collections.singletonMap(getConsumerUrl().getServiceKey(), invokers.size());
}
@Override
public String toString() {
return "Directory(" + "invokers: "
+ invokers.size() + "["
+ invokers.stream()
.map(Invoker::getUrl)
.map(URL::getAddress)
.limit(3)
.collect(Collectors.joining(", "))
+ "]" + ", validInvokers: "
+ validInvokers.size() + "["
+ validInvokers.stream()
.map(Invoker::getUrl)
.map(URL::getAddress)
.limit(3)
.collect(Collectors.joining(", "))
+ "]" + ", invokersToReconnect: "
+ invokersToReconnect.size() + "["
+ invokersToReconnect.stream()
.map(Invoker::getUrl)
.map(URL::getAddress)
.limit(3)
.collect(Collectors.joining(", "))
+ "]" + ')';
}
} }

View File

@ -17,30 +17,22 @@
package org.apache.dubbo.rpc.cluster.directory; package org.apache.dubbo.rpc.cluster.directory;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.RouterChain; import org.apache.dubbo.rpc.cluster.RouterChain;
import org.apache.dubbo.rpc.cluster.SingleRouterChain;
import org.apache.dubbo.rpc.cluster.router.state.BitList; import org.apache.dubbo.rpc.cluster.router.state.BitList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_SITE_SELECTION;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTER_MODE_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
/** /**
* StaticDirectory * StaticDirectory
*/ */
public class StaticDirectory<T> extends AbstractDirectory<T> { public class StaticDirectory<T> extends AbstractDirectory<T> {
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(StaticDirectory.class); private static final Logger logger = LoggerFactory.getLogger(StaticDirectory.class);
private final Class<T> interfaceClass;
public StaticDirectory(List<Invoker<T>> invokers) { public StaticDirectory(List<Invoker<T>> invokers) {
this(null, invokers, null); this(null, invokers, null);
@ -55,22 +47,16 @@ public class StaticDirectory<T> extends AbstractDirectory<T> {
} }
public StaticDirectory(URL url, List<Invoker<T>> invokers, RouterChain<T> routerChain) { public StaticDirectory(URL url, List<Invoker<T>> invokers, RouterChain<T> routerChain) {
super( super(url == null && CollectionUtils.isNotEmpty(invokers) ? invokers.get(0).getUrl() : url, routerChain, false);
url == null && CollectionUtils.isNotEmpty(invokers)
? invokers.get(0).getUrl()
: url,
routerChain,
false);
if (CollectionUtils.isEmpty(invokers)) { if (CollectionUtils.isEmpty(invokers)) {
throw new IllegalArgumentException("invokers == null"); throw new IllegalArgumentException("invokers == null");
} }
this.setInvokers(new BitList<>(invokers)); this.setInvokers(new BitList<>(invokers));
this.interfaceClass = invokers.get(0).getInterface();
} }
@Override @Override
public Class<T> getInterface() { public Class<T> getInterface() {
return interfaceClass; return getInvokers().get(0).getInterface();
} }
@Override @Override
@ -86,8 +72,6 @@ public class StaticDirectory<T> extends AbstractDirectory<T> {
for (Invoker<T> invoker : getValidInvokers()) { for (Invoker<T> invoker : getValidInvokers()) {
if (invoker.isAvailable()) { if (invoker.isAvailable()) {
return true; return true;
} else {
addInvalidateInvoker(invoker);
} }
} }
return false; return false;
@ -106,45 +90,29 @@ public class StaticDirectory<T> extends AbstractDirectory<T> {
public void buildRouterChain() { public void buildRouterChain() {
RouterChain<T> routerChain = RouterChain.buildChain(getInterface(), getUrl()); RouterChain<T> routerChain = RouterChain.buildChain(getInterface(), getUrl());
routerChain.setInvokers(getInvokers(), () -> {}); routerChain.setInvokers(getInvokers());
this.setRouterChain(routerChain); this.setRouterChain(routerChain);
} }
public void notify(List<Invoker<T>> invokers) { public void notify(List<Invoker<T>> invokers) {
BitList<Invoker<T>> bitList = new BitList<>(invokers); this.setInvokers(new BitList<>(invokers));
if (routerChain != null) { if (routerChain != null) {
refreshRouter(bitList.clone(), () -> this.setInvokers(bitList)); routerChain.setInvokers(this.getInvokers());
} else {
this.setInvokers(bitList);
} }
} }
@Override @Override
protected List<Invoker<T>> doList( protected List<Invoker<T>> doList(BitList<Invoker<T>> invokers, Invocation invocation) throws RpcException {
SingleRouterChain<T> singleRouterChain, BitList<Invoker<T>> invokers, Invocation invocation) if (routerChain != null) {
throws RpcException {
if (singleRouterChain != null) {
try { try {
List<Invoker<T>> finalInvokers = singleRouterChain.route(getConsumerUrl(), invokers, invocation); List<Invoker<T>> finalInvokers = routerChain.route(getConsumerUrl(), invokers, invocation);
return finalInvokers == null ? BitList.emptyList() : finalInvokers; return finalInvokers == null ? BitList.emptyList() : finalInvokers;
} catch (Throwable t) { } catch (Throwable t) {
logger.error( logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
CLUSTER_FAILED_SITE_SELECTION,
"Failed to execute router",
"",
"Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(),
t);
return BitList.emptyList(); return BitList.emptyList();
} }
} }
return invokers; return invokers;
} }
@Override
protected Map<String, String> getDirectoryMeta() {
Map<String, String> metas = new HashMap<>();
metas.put(REGISTRY_KEY, "static");
metas.put(REGISTER_MODE_KEY, "static");
return metas;
}
} }

View File

@ -21,4 +21,5 @@ import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.rpc.BaseFilter; import org.apache.dubbo.rpc.BaseFilter;
@SPI(scope = ExtensionScope.MODULE) @SPI(scope = ExtensionScope.MODULE)
public interface ClusterFilter extends BaseFilter {} public interface ClusterFilter extends BaseFilter {
}

View File

@ -19,7 +19,7 @@ package org.apache.dubbo.rpc.cluster.filter;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.extension.ExtensionDirector; import org.apache.dubbo.common.extension.ExtensionDirector;
import org.apache.dubbo.common.extension.support.ActivateComparator; import org.apache.dubbo.common.extension.support.MultiInstanceActivateComparator;
import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.rpc.Filter; import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
@ -47,14 +47,12 @@ public class DefaultFilterChainBuilder implements FilterChainBuilder {
List<ModuleModel> moduleModels = getModuleModelsFromUrl(url); List<ModuleModel> moduleModels = getModuleModelsFromUrl(url);
List<Filter> filters; List<Filter> filters;
if (moduleModels != null && moduleModels.size() == 1) { if (moduleModels != null && moduleModels.size() == 1) {
filters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModels.get(0)) filters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModels.get(0)).getActivateExtension(url, key, group);
.getActivateExtension(url, key, group);
} else if (moduleModels != null && moduleModels.size() > 1) { } else if (moduleModels != null && moduleModels.size() > 1) {
filters = new ArrayList<>(); filters = new ArrayList<>();
List<ExtensionDirector> directors = new ArrayList<>(); List<ExtensionDirector> directors = new ArrayList<>();
for (ModuleModel moduleModel : moduleModels) { for (ModuleModel moduleModel : moduleModels) {
List<Filter> tempFilters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModel) List<Filter> tempFilters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModel).getActivateExtension(url, key, group);
.getActivateExtension(url, key, group);
filters.addAll(tempFilters); filters.addAll(tempFilters);
directors.add(moduleModel.getExtensionDirector()); directors.add(moduleModel.getExtensionDirector());
} }
@ -64,6 +62,7 @@ public class DefaultFilterChainBuilder implements FilterChainBuilder {
filters = ScopeModelUtil.getExtensionLoader(Filter.class, null).getActivateExtension(url, key, group); filters = ScopeModelUtil.getExtensionLoader(Filter.class, null).getActivateExtension(url, key, group);
} }
if (!CollectionUtils.isEmpty(filters)) { if (!CollectionUtils.isEmpty(filters)) {
for (int i = filters.size() - 1; i >= 0; i--) { for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i); final Filter filter = filters.get(i);
@ -80,29 +79,25 @@ public class DefaultFilterChainBuilder implements FilterChainBuilder {
* build consumer cluster filter chain * build consumer cluster filter chain
*/ */
@Override @Override
public <T> ClusterInvoker<T> buildClusterInvokerChain( public <T> ClusterInvoker<T> buildClusterInvokerChain(final ClusterInvoker<T> originalInvoker, String key, String group) {
final ClusterInvoker<T> originalInvoker, String key, String group) {
ClusterInvoker<T> last = originalInvoker; ClusterInvoker<T> last = originalInvoker;
URL url = originalInvoker.getUrl(); URL url = originalInvoker.getUrl();
List<ModuleModel> moduleModels = getModuleModelsFromUrl(url); List<ModuleModel> moduleModels = getModuleModelsFromUrl(url);
List<ClusterFilter> filters; List<ClusterFilter> filters;
if (moduleModels != null && moduleModels.size() == 1) { if (moduleModels != null && moduleModels.size() == 1) {
filters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, moduleModels.get(0)) filters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, moduleModels.get(0)).getActivateExtension(url, key, group);
.getActivateExtension(url, key, group);
} else if (moduleModels != null && moduleModels.size() > 1) { } else if (moduleModels != null && moduleModels.size() > 1) {
filters = new ArrayList<>(); filters = new ArrayList<>();
List<ExtensionDirector> directors = new ArrayList<>(); List<ExtensionDirector> directors = new ArrayList<>();
for (ModuleModel moduleModel : moduleModels) { for (ModuleModel moduleModel : moduleModels) {
List<ClusterFilter> tempFilters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, moduleModel) List<ClusterFilter> tempFilters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, moduleModel).getActivateExtension(url, key, group);
.getActivateExtension(url, key, group);
filters.addAll(tempFilters); filters.addAll(tempFilters);
directors.add(moduleModel.getExtensionDirector()); directors.add(moduleModel.getExtensionDirector());
} }
filters = sortingAndDeduplication(filters, directors); filters = sortingAndDeduplication(filters, directors);
} else { } else {
filters = filters = ScopeModelUtil.getExtensionLoader(ClusterFilter.class, null).getActivateExtension(url, key, group);
ScopeModelUtil.getExtensionLoader(ClusterFilter.class, null).getActivateExtension(url, key, group);
} }
if (!CollectionUtils.isEmpty(filters)) { if (!CollectionUtils.isEmpty(filters)) {
@ -118,7 +113,7 @@ public class DefaultFilterChainBuilder implements FilterChainBuilder {
} }
private <T> List<T> sortingAndDeduplication(List<T> filters, List<ExtensionDirector> directors) { private <T> List<T> sortingAndDeduplication(List<T> filters, List<ExtensionDirector> directors) {
Map<Class<?>, T> filtersSet = new TreeMap<>(new ActivateComparator(directors)); Map<Class<?>, T> filtersSet = new TreeMap<>(new MultiInstanceActivateComparator(directors));
for (T filter : filters) { for (T filter : filters) {
filtersSet.putIfAbsent(filter.getClass(), filter); filtersSet.putIfAbsent(filter.getClass(), filter);
} }
@ -146,4 +141,5 @@ public class DefaultFilterChainBuilder implements FilterChainBuilder {
} }
return moduleModels; return moduleModels;
} }
} }

View File

@ -19,9 +19,8 @@ package org.apache.dubbo.rpc.cluster.filter;
import org.apache.dubbo.common.Experimental; import org.apache.dubbo.common.Experimental;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.BaseFilter; import org.apache.dubbo.rpc.BaseFilter;
import org.apache.dubbo.rpc.Filter; import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
@ -36,8 +35,6 @@ import org.apache.dubbo.rpc.cluster.Directory;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_EXECUTE_FILTER_EXCEPTION;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.INTERNAL_ERROR;
import static org.apache.dubbo.common.extension.ExtensionScope.APPLICATION; import static org.apache.dubbo.common.extension.ExtensionScope.APPLICATION;
@SPI(value = "default", scope = APPLICATION) @SPI(value = "default", scope = APPLICATION)
@ -92,8 +89,7 @@ public interface FilterChainBuilder {
public Result invoke(Invocation invocation) throws RpcException { public Result invoke(Invocation invocation) throws RpcException {
Result asyncResult; Result asyncResult;
try { try {
InvocationProfilerUtils.enterDetailProfiler( InvocationProfilerUtils.enterDetailProfiler(invocation, () -> "Filter " + filter.getClass().getName() + " invoke.");
invocation, () -> "Filter " + filter.getClass().getName() + " invoke.");
asyncResult = filter.invoke(nextNode, invocation); asyncResult = filter.invoke(nextNode, invocation);
} catch (Exception e) { } catch (Exception e) {
InvocationProfilerUtils.releaseDetailProfiler(invocation); InvocationProfilerUtils.releaseDetailProfiler(invocation);
@ -160,11 +156,12 @@ public interface FilterChainBuilder {
* @param <TYPE> * @param <TYPE>
*/ */
class ClusterFilterChainNode<T, TYPE extends ClusterInvoker<T>, FILTER extends BaseFilter> class ClusterFilterChainNode<T, TYPE extends ClusterInvoker<T>, FILTER extends BaseFilter>
extends FilterChainNode<T, TYPE, FILTER> implements ClusterInvoker<T> { extends FilterChainNode<T, TYPE, FILTER> implements ClusterInvoker<T> {
public ClusterFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) { public ClusterFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) {
super(originalInvoker, nextNode, filter); super(originalInvoker, nextNode, filter);
} }
@Override @Override
public URL getRegistryUrl() { public URL getRegistryUrl() {
return getOriginalInvoker().getRegistryUrl(); return getOriginalInvoker().getRegistryUrl();
@ -182,8 +179,7 @@ public interface FilterChainBuilder {
} }
class CallbackRegistrationInvoker<T, FILTER extends BaseFilter> implements Invoker<T> { class CallbackRegistrationInvoker<T, FILTER extends BaseFilter> implements Invoker<T> {
private static final ErrorTypeAwareLogger LOGGER = static final Logger LOGGER = LoggerFactory.getLogger(CallbackRegistrationInvoker.class);
LoggerFactory.getErrorTypeAwareLogger(CallbackRegistrationInvoker.class);
final Invoker<T> filterInvoker; final Invoker<T> filterInvoker;
final List<FILTER> filters; final List<FILTER> filters;
@ -224,20 +220,9 @@ public interface FilterChainBuilder {
} }
} }
} catch (RuntimeException runtimeException) { } catch (RuntimeException runtimeException) {
LOGGER.error( LOGGER.error(String.format("Exception occurred while executing the %s filter named %s.", i, filter.getClass().getSimpleName()));
CLUSTER_EXECUTE_FILTER_EXCEPTION,
"the custom filter is abnormal",
"",
String.format(
"Exception occurred while executing the %s filter named %s.",
i, filter.getClass().getSimpleName()));
if (LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format( LOGGER.debug(String.format("Whole filter list is: %s", filters.stream().map(tmpFilter -> tmpFilter.getClass().getSimpleName()).collect(Collectors.toList())));
"Whole filter list is: %s",
filters.stream()
.map(tmpFilter ->
tmpFilter.getClass().getSimpleName())
.collect(Collectors.toList())));
} }
filterRuntimeException = runtimeException; filterRuntimeException = runtimeException;
t = runtimeException; t = runtimeException;
@ -251,10 +236,6 @@ public interface FilterChainBuilder {
return asyncResult; return asyncResult;
} }
public Invoker<T> getFilterInvoker() {
return filterInvoker;
}
@Override @Override
public Class<T> getInterface() { public Class<T> getInterface() {
return filterInvoker.getInterface(); return filterInvoker.getInterface();
@ -276,12 +257,11 @@ public interface FilterChainBuilder {
} }
} }
class ClusterCallbackRegistrationInvoker<T, FILTER extends BaseFilter> class ClusterCallbackRegistrationInvoker<T, FILTER extends BaseFilter> extends CallbackRegistrationInvoker<T, FILTER>
extends CallbackRegistrationInvoker<T, FILTER> implements ClusterInvoker<T> { implements ClusterInvoker<T> {
private ClusterInvoker<T> originalInvoker; private ClusterInvoker<T> originalInvoker;
public ClusterCallbackRegistrationInvoker( public ClusterCallbackRegistrationInvoker(ClusterInvoker<T> originalInvoker, Invoker<T> filterInvoker, List<FILTER> filters) {
ClusterInvoker<T> originalInvoker, Invoker<T> filterInvoker, List<FILTER> filters) {
super(filterInvoker, filters); super(filterInvoker, filters);
this.originalInvoker = originalInvoker; this.originalInvoker = originalInvoker;
} }
@ -306,11 +286,9 @@ public interface FilterChainBuilder {
} }
} }
@Experimental(
"Works for the same purpose as FilterChainNode, replace FilterChainNode with this one when proved stable enough") @Experimental("Works for the same purpose as FilterChainNode, replace FilterChainNode with this one when proved stable enough")
class CopyOfFilterChainNode<T, TYPE extends Invoker<T>, FILTER extends BaseFilter> implements Invoker<T> { class CopyOfFilterChainNode<T, TYPE extends Invoker<T>, FILTER extends BaseFilter> implements Invoker<T> {
private static final ErrorTypeAwareLogger LOGGER =
LoggerFactory.getErrorTypeAwareLogger(CopyOfFilterChainNode.class);
TYPE originalInvoker; TYPE originalInvoker;
Invoker<T> nextNode; Invoker<T> nextNode;
FILTER filter; FILTER filter;
@ -344,17 +322,8 @@ public interface FilterChainBuilder {
public Result invoke(Invocation invocation) throws RpcException { public Result invoke(Invocation invocation) throws RpcException {
Result asyncResult; Result asyncResult;
try { try {
InvocationProfilerUtils.enterDetailProfiler( InvocationProfilerUtils.enterDetailProfiler(invocation, () -> "Filter " + filter.getClass().getName() + " invoke.");
invocation, () -> "Filter " + filter.getClass().getName() + " invoke.");
asyncResult = filter.invoke(nextNode, invocation); asyncResult = filter.invoke(nextNode, invocation);
if (!(asyncResult instanceof AsyncRpcResult)) {
String msg =
"The result of filter invocation must be AsyncRpcResult. (If you want to recreate a result, please use AsyncRpcResult.newDefaultAsyncResult.) "
+ "Filter class: " + filter.getClass().getName() + ". Result class: "
+ asyncResult.getClass().getName() + ".";
LOGGER.error(INTERNAL_ERROR, "", "", msg);
throw new RpcException(msg);
}
} catch (Exception e) { } catch (Exception e) {
InvocationProfilerUtils.releaseDetailProfiler(invocation); InvocationProfilerUtils.releaseDetailProfiler(invocation);
if (filter instanceof ListenableFilter) { if (filter instanceof ListenableFilter) {
@ -389,14 +358,14 @@ public interface FilterChainBuilder {
} }
} }
@Experimental( @Experimental("Works for the same purpose as ClusterFilterChainNode, replace ClusterFilterChainNode with this one when proved stable enough")
"Works for the same purpose as ClusterFilterChainNode, replace ClusterFilterChainNode with this one when proved stable enough")
class CopyOfClusterFilterChainNode<T, TYPE extends ClusterInvoker<T>, FILTER extends BaseFilter> class CopyOfClusterFilterChainNode<T, TYPE extends ClusterInvoker<T>, FILTER extends BaseFilter>
extends CopyOfFilterChainNode<T, TYPE, FILTER> implements ClusterInvoker<T> { extends CopyOfFilterChainNode<T, TYPE, FILTER> implements ClusterInvoker<T> {
public CopyOfClusterFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) { public CopyOfClusterFilterChainNode(TYPE originalInvoker, Invoker<T> nextNode, FILTER filter) {
super(originalInvoker, nextNode, filter); super(originalInvoker, nextNode, filter);
} }
@Override @Override
public URL getRegistryUrl() { public URL getRegistryUrl() {
return getOriginalInvoker().getRegistryUrl(); return getOriginalInvoker().getRegistryUrl();

View File

@ -62,8 +62,7 @@ public class ProtocolFilterWrapper implements Protocol {
} }
private <T> FilterChainBuilder getFilterChainBuilder(URL url) { private <T> FilterChainBuilder getFilterChainBuilder(URL url) {
return ScopeModelUtil.getExtensionLoader(FilterChainBuilder.class, url.getScopeModel()) return ScopeModelUtil.getExtensionLoader(FilterChainBuilder.class, url.getScopeModel()).getDefaultExtension();
.getDefaultExtension();
} }
@Override @Override
@ -84,4 +83,5 @@ public class ProtocolFilterWrapper implements Protocol {
public List<ProtocolServer> getServers() { public List<ProtocolServer> getServers() {
return protocol.getServers(); return protocol.getServers();
} }
} }

View File

@ -1,45 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.rpc.cluster.filter.support;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
import org.apache.dubbo.rpc.model.ServiceModel;
import java.util.Optional;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
@Activate(group = CONSUMER, order = Integer.MIN_VALUE + 100)
public class ConsumerClassLoaderFilter implements ClusterFilter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
ClassLoader originClassLoader = Thread.currentThread().getContextClassLoader();
try {
Optional.ofNullable(invocation.getServiceModel())
.map(ServiceModel::getClassLoader)
.ifPresent(Thread.currentThread()::setContextClassLoader);
return invoker.invoke(invocation);
} finally {
Thread.currentThread().setContextClassLoader(originClassLoader);
}
}
}

View File

@ -19,6 +19,7 @@ package org.apache.dubbo.rpc.cluster.filter.support;
import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.Filter; import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
@ -32,13 +33,11 @@ import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.TimeoutCountDown; import org.apache.dubbo.rpc.TimeoutCountDown;
import org.apache.dubbo.rpc.cluster.filter.ClusterFilter; import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.support.RpcUtils;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER; import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
import static org.apache.dubbo.common.constants.CommonConstants.ENABLE_TIMEOUT_COUNTDOWN_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY; import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.TIME_COUNTDOWN_KEY; import static org.apache.dubbo.common.constants.CommonConstants.TIME_COUNTDOWN_KEY;
@ -55,75 +54,70 @@ public class ConsumerContextFilter implements ClusterFilter, ClusterFilter.Liste
private Set<PenetrateAttachmentSelector> supportedSelectors; private Set<PenetrateAttachmentSelector> supportedSelectors;
public ConsumerContextFilter(ApplicationModel applicationModel) { public ConsumerContextFilter(ApplicationModel applicationModel) {
ExtensionLoader<PenetrateAttachmentSelector> selectorExtensionLoader = ExtensionLoader<PenetrateAttachmentSelector> selectorExtensionLoader = applicationModel.getExtensionLoader(PenetrateAttachmentSelector.class);
applicationModel.getExtensionLoader(PenetrateAttachmentSelector.class);
supportedSelectors = selectorExtensionLoader.getSupportedExtensionInstances(); supportedSelectors = selectorExtensionLoader.getSupportedExtensionInstances();
} }
@Override @Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
RpcContext.getServiceContext().setInvoker(invoker).setInvocation(invocation); RpcContext.RestoreServiceContext originServiceContext = RpcContext.storeServiceContext();
try {
RpcContext.getServiceContext()
.setInvoker(invoker)
.setInvocation(invocation)
.setLocalAddress(NetUtils.getLocalHost(), 0);
RpcContext context = RpcContext.getClientAttachment(); RpcContext context = RpcContext.getClientAttachment();
context.setAttachment(REMOTE_APPLICATION_KEY, invoker.getUrl().getApplication()); context.setAttachment(REMOTE_APPLICATION_KEY, invoker.getUrl().getApplication());
if (invocation instanceof RpcInvocation) { if (invocation instanceof RpcInvocation) {
((RpcInvocation) invocation).setInvoker(invoker); ((RpcInvocation) invocation).setInvoker(invoker);
}
if (CollectionUtils.isNotEmpty(supportedSelectors)) {
for (PenetrateAttachmentSelector supportedSelector : supportedSelectors) {
Map<String, Object> selected = supportedSelector.select(
invocation, RpcContext.getClientAttachment(), RpcContext.getServerAttachment());
if (CollectionUtils.isNotEmptyMap(selected)) {
((RpcInvocation) invocation).addObjectAttachments(selected);
}
} }
} else {
((RpcInvocation) invocation)
.addObjectAttachments(RpcContext.getServerAttachment().getObjectAttachments());
}
Map<String, Object> contextAttachments =
RpcContext.getClientAttachment().getObjectAttachments();
if (CollectionUtils.isNotEmptyMap(contextAttachments)) {
/**
* invocation.addAttachmentsIfAbsent(context){@link RpcInvocation#addAttachmentsIfAbsent(Map)}should not be used here,
* because the {@link RpcContext#setAttachment(String, String)} is passed in the Filter when the call is triggered
* by the built-in retry mechanism of the Dubbo. The attachment to update RpcContext will no longer work, which is
* a mistake in most cases (for example, through Filter to RpcContext output traceId and spanId and other information).
*/
((RpcInvocation) invocation).addObjectAttachments(contextAttachments);
}
// pass default timeout set by end user (ReferenceConfig) if (CollectionUtils.isNotEmpty(supportedSelectors)) {
Object countDown = RpcContext.getServerAttachment().getObjectAttachment(TIME_COUNTDOWN_KEY); for (PenetrateAttachmentSelector supportedSelector : supportedSelectors) {
if (countDown != null) { Map<String, Object> selected = supportedSelector.select();
String methodName = RpcUtils.getMethodName(invocation); if (CollectionUtils.isNotEmptyMap(selected)) {
// When the client has enabled the timeout-countdown function, ((RpcInvocation) invocation).addObjectAttachments(selected);
// the subsequent calls launched by the Server side will be enabled by default, }
// and support to turn off the function on a node to get rid of the timeout control. }
if (invoker.getUrl().getMethodParameter(methodName, ENABLE_TIMEOUT_COUNTDOWN_KEY, true)) { } else {
context.setObjectAttachment(TIME_COUNTDOWN_KEY, countDown); ((RpcInvocation) invocation).addObjectAttachments(RpcContext.getServerAttachment().getObjectAttachments());
}
Map<String, Object> contextAttachments = RpcContext.getClientAttachment().getObjectAttachments();
if (CollectionUtils.isNotEmptyMap(contextAttachments)) {
/**
* invocation.addAttachmentsIfAbsent(context){@link RpcInvocation#addAttachmentsIfAbsent(Map)}should not be used here,
* because the {@link RpcContext#setAttachment(String, String)} is passed in the Filter when the call is triggered
* by the built-in retry mechanism of the Dubbo. The attachment to update RpcContext will no longer work, which is
* a mistake in most cases (for example, through Filter to RpcContext output traceId and spanId and other information).
*/
((RpcInvocation) invocation).addObjectAttachments(contextAttachments);
}
// pass default timeout set by end user (ReferenceConfig)
Object countDown = context.getObjectAttachment(TIME_COUNTDOWN_KEY);
if (countDown != null) {
TimeoutCountDown timeoutCountDown = (TimeoutCountDown) countDown; TimeoutCountDown timeoutCountDown = (TimeoutCountDown) countDown;
if (timeoutCountDown.isExpired()) { if (timeoutCountDown.isExpired()) {
return AsyncRpcResult.newDefaultAsyncResult( return AsyncRpcResult.newDefaultAsyncResult(new RpcException(RpcException.TIMEOUT_TERMINATE,
new RpcException( "No time left for making the following call: " + invocation.getServiceName() + "."
RpcException.TIMEOUT_TERMINATE, + invocation.getMethodName() + ", terminate directly."), invocation);
"No time left for making the following call: " + invocation.getServiceName() + "."
+ RpcUtils.getMethodName(invocation) + ", terminate directly."),
invocation);
} }
} }
RpcContext.removeServerContext();
return invoker.invoke(invocation);
} finally {
RpcContext.restoreServiceContext(originServiceContext);
} }
RpcContext.removeClientResponseContext();
return invoker.invoke(invocation);
} }
@Override @Override
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) { public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
// pass attachments to result // pass attachments to result
Map<String, Object> map = appResponse.getObjectAttachments(); RpcContext.getServerContext().setObjectAttachments(appResponse.getObjectAttachments());
RpcContext.getClientResponseContext().setObjectAttachments(map);
removeContext(invocation); removeContext(invocation);
} }
@ -138,15 +132,14 @@ public class ConsumerContextFilter implements ClusterFilter, ClusterFilter.Liste
RpcInvocation rpcInvocation = (RpcInvocation) invocation; RpcInvocation rpcInvocation = (RpcInvocation) invocation;
if (rpcInvocation.getInvokeMode() != null) { if (rpcInvocation.getInvokeMode() != null) {
// clear service context if not in sync mode // clear service context if not in sync mode
if (rpcInvocation.getInvokeMode() == InvokeMode.ASYNC if (rpcInvocation.getInvokeMode() == InvokeMode.ASYNC || rpcInvocation.getInvokeMode() == InvokeMode.FUTURE) {
|| rpcInvocation.getInvokeMode() == InvokeMode.FUTURE) {
RpcContext.removeServiceContext(); RpcContext.removeServiceContext();
} }
} }
} }
// server context must not be removed because user might use it on callback. // server context must not be removed because user might use it on callback.
// So the clear of is delayed til the start of the next rpc call, see RpcContext.removeServerContext(); in // So the clear of is delayed til the start of the next rpc call, see RpcContext.removeServerContext(); in invoke() above
// invoke() above
// RpcContext.removeServerContext(); // RpcContext.removeServerContext();
} }
} }

View File

@ -1,88 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.rpc.cluster.filter.support;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.metrics.collector.DefaultMetricsCollector;
import org.apache.dubbo.metrics.event.MetricsDispatcher;
import org.apache.dubbo.metrics.event.MetricsEventBus;
import org.apache.dubbo.metrics.event.RequestEvent;
import org.apache.dubbo.metrics.model.MethodMetric;
import org.apache.dubbo.rpc.BaseFilter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ScopeModelAware;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER_SIDE;
@Activate(group = CONSUMER, onClass = "org.apache.dubbo.metrics.collector.DefaultMetricsCollector")
public class MetricsClusterFilter implements ClusterFilter, BaseFilter.Listener, ScopeModelAware {
private ApplicationModel applicationModel;
private DefaultMetricsCollector collector;
private String appName;
private MetricsDispatcher metricsDispatcher;
private boolean serviceLevel;
@Override
public void setApplicationModel(ApplicationModel applicationModel) {
this.applicationModel = applicationModel;
this.collector = applicationModel.getBeanFactory().getBean(DefaultMetricsCollector.class);
this.appName = applicationModel.tryGetApplicationName();
this.metricsDispatcher = applicationModel.getBeanFactory().getBean(MetricsDispatcher.class);
this.serviceLevel = MethodMetric.isServiceLevel(applicationModel);
}
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
return invoker.invoke(invocation);
}
@Override
public void onResponse(Result result, Invoker<?> invoker, Invocation invocation) {
handleMethodException(result.getException(), invocation);
}
@Override
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
handleMethodException(t, invocation);
}
private void handleMethodException(Throwable t, Invocation invocation) {
if (collector == null || !collector.isCollectEnabled()) {
return;
}
if (t instanceof RpcException) {
RpcException e = (RpcException) t;
if (e.isForbidden()) {
MetricsEventBus.publish(RequestEvent.toRequestErrorEvent(
applicationModel,
appName,
metricsDispatcher,
invocation,
CONSUMER_SIDE,
e.getCode(),
serviceLevel));
}
}
}
}

View File

@ -1,50 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.rpc.cluster.filter.support;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.metrics.filter.MetricsFilter;
import org.apache.dubbo.rpc.BaseFilter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
@Activate(
group = {CONSUMER},
order = Integer.MIN_VALUE + 100)
public class MetricsConsumerFilter extends MetricsFilter implements ClusterFilter, BaseFilter.Listener {
public MetricsConsumerFilter() {}
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
return super.invoke(invoker, invocation, false);
}
@Override
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
super.onResponse(appResponse, invoker, invocation, false);
}
@Override
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
super.onError(t, invoker, invocation, false);
}
}

View File

@ -1,96 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.rpc.cluster.filter.support;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.metrics.observation.DefaultDubboClientObservationConvention;
import org.apache.dubbo.metrics.observation.DubboClientContext;
import org.apache.dubbo.metrics.observation.DubboClientObservationConvention;
import org.apache.dubbo.metrics.observation.DubboObservationDocumentation;
import org.apache.dubbo.rpc.BaseFilter;
import org.apache.dubbo.rpc.Filter;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.filter.ClusterFilter;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ScopeModelAware;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
/**
* A {@link Filter} that creates an {@link Observation} around the outgoing message.
*/
@Activate(group = CONSUMER, order = -1, onClass = "io.micrometer.observation.NoopObservationRegistry")
public class ObservationSenderFilter implements ClusterFilter, BaseFilter.Listener, ScopeModelAware {
private ObservationRegistry observationRegistry;
private DubboClientObservationConvention clientObservationConvention;
public ObservationSenderFilter(ApplicationModel applicationModel) {
applicationModel.getApplicationConfigManager().getTracing().ifPresent(cfg -> {
if (Boolean.TRUE.equals(cfg.getEnabled())) {
observationRegistry = applicationModel.getBeanFactory().getBean(ObservationRegistry.class);
clientObservationConvention =
applicationModel.getBeanFactory().getBean(DubboClientObservationConvention.class);
}
});
}
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
if (observationRegistry == null) {
return invoker.invoke(invocation);
}
final DubboClientContext senderContext = new DubboClientContext(invoker, invocation);
final Observation observation = DubboObservationDocumentation.CLIENT.observation(
this.clientObservationConvention,
DefaultDubboClientObservationConvention.getInstance(),
() -> senderContext,
observationRegistry);
invocation.put(Observation.class, observation.start());
return observation.scoped(() -> invoker.invoke(invocation));
}
@Override
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
final Observation observation = getObservation(invocation);
if (observation == null) {
return;
}
observation.stop();
}
@Override
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
final Observation observation = getObservation(invocation);
if (observation == null) {
return;
}
observation.error(t);
observation.stop();
}
private Observation getObservation(Invocation invocation) {
return (Observation) invocation.get(Observation.class);
}
}

View File

@ -22,7 +22,7 @@ import org.apache.dubbo.rpc.model.ModuleModel;
public class DefaultGovernanceRuleRepositoryImpl implements GovernanceRuleRepository { public class DefaultGovernanceRuleRepositoryImpl implements GovernanceRuleRepository {
private final ModuleModel moduleModel; private ModuleModel moduleModel;
public DefaultGovernanceRuleRepositoryImpl(ModuleModel moduleModel) { public DefaultGovernanceRuleRepositoryImpl(ModuleModel moduleModel) {
this.moduleModel = moduleModel; this.moduleModel = moduleModel;
@ -54,6 +54,7 @@ public class DefaultGovernanceRuleRepositoryImpl implements GovernanceRuleReposi
} }
private DynamicConfiguration getDynamicConfiguration() { private DynamicConfiguration getDynamicConfiguration() {
return moduleModel.modelEnvironment().getDynamicConfiguration().orElse(null); return moduleModel.getModelEnvironment().getDynamicConfiguration().orElse(null);
} }
} }

View File

@ -36,6 +36,7 @@ public interface GovernanceRuleRepository {
addListener(key, DEFAULT_GROUP, listener); addListener(key, DEFAULT_GROUP, listener);
} }
/** /**
* {@link #removeListener(String, String, ConfigurationListener)} * {@link #removeListener(String, String, ConfigurationListener)}
* *

View File

@ -22,7 +22,6 @@ import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.cluster.ClusterInvoker; import org.apache.dubbo.rpc.cluster.ClusterInvoker;
import org.apache.dubbo.rpc.cluster.LoadBalance; import org.apache.dubbo.rpc.cluster.LoadBalance;
import org.apache.dubbo.rpc.support.RpcUtils;
import java.util.List; import java.util.List;
@ -47,7 +46,7 @@ public abstract class AbstractLoadBalance implements LoadBalance {
* @return weight which takes warmup into account * @return weight which takes warmup into account
*/ */
static int calculateWarmupWeight(int uptime, int warmup, int weight) { static int calculateWarmupWeight(int uptime, int warmup, int weight) {
int ww = (int) (uptime / ((float) warmup / weight)); int ww = (int) ( uptime / ((float) warmup / weight));
return ww < 1 ? 1 : (Math.min(ww, weight)); return ww < 1 ? 1 : (Math.min(ww, weight));
} }
@ -64,6 +63,7 @@ public abstract class AbstractLoadBalance implements LoadBalance {
protected abstract <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation); protected abstract <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation);
/** /**
* Get the weight of the invoker's invocation which takes warmup time into account * Get the weight of the invoker's invocation which takes warmup time into account
* if the uptime is within the warmup time, the weight will be reduce proportionally * if the uptime is within the warmup time, the weight will be reduce proportionally
@ -83,7 +83,7 @@ public abstract class AbstractLoadBalance implements LoadBalance {
if (REGISTRY_SERVICE_REFERENCE_PATH.equals(url.getServiceInterface())) { if (REGISTRY_SERVICE_REFERENCE_PATH.equals(url.getServiceInterface())) {
weight = url.getParameter(WEIGHT_KEY, DEFAULT_WEIGHT); weight = url.getParameter(WEIGHT_KEY, DEFAULT_WEIGHT);
} else { } else {
weight = url.getMethodParameter(RpcUtils.getMethodName(invocation), WEIGHT_KEY, DEFAULT_WEIGHT); weight = url.getMethodParameter(invocation.getMethodName(), WEIGHT_KEY, DEFAULT_WEIGHT);
if (weight > 0) { if (weight > 0) {
long timestamp = invoker.getUrl().getParameter(TIMESTAMP_KEY, 0L); long timestamp = invoker.getUrl().getParameter(TIMESTAMP_KEY, 0L);
if (timestamp > 0L) { if (timestamp > 0L) {
@ -93,7 +93,7 @@ public abstract class AbstractLoadBalance implements LoadBalance {
} }
int warmup = invoker.getUrl().getParameter(WARMUP_KEY, DEFAULT_WARMUP); int warmup = invoker.getUrl().getParameter(WARMUP_KEY, DEFAULT_WARMUP);
if (uptime > 0 && uptime < warmup) { if (uptime > 0 && uptime < warmup) {
weight = calculateWarmupWeight((int) uptime, warmup, weight); weight = calculateWarmupWeight((int)uptime, warmup, weight);
} }
} }
} }

View File

@ -1,135 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.dubbo.rpc.cluster.loadbalance;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.LoadbalanceRules;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.AdaptiveMetrics;
import org.apache.dubbo.rpc.Constants;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.support.RpcUtils;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;
import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;
/**
* AdaptiveLoadBalance
* </p>
*/
public class AdaptiveLoadBalance extends AbstractLoadBalance {
public static final String NAME = "adaptive";
// default key
private String attachmentKey = "mem,load";
private final AdaptiveMetrics adaptiveMetrics;
public AdaptiveLoadBalance(ApplicationModel scopeModel) {
adaptiveMetrics = scopeModel.getBeanFactory().getBean(AdaptiveMetrics.class);
}
@Override
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
Invoker<T> invoker = selectByP2C(invokers, invocation);
invocation.setAttachment(Constants.ADAPTIVE_LOADBALANCE_ATTACHMENT_KEY, attachmentKey);
long startTime = System.currentTimeMillis();
invocation.getAttributes().put(Constants.ADAPTIVE_LOADBALANCE_START_TIME, startTime);
invocation.getAttributes().put(LOADBALANCE_KEY, LoadbalanceRules.ADAPTIVE);
adaptiveMetrics.addConsumerReq(getServiceKey(invoker, invocation));
adaptiveMetrics.setPickTime(getServiceKey(invoker, invocation), startTime);
return invoker;
}
private <T> Invoker<T> selectByP2C(List<Invoker<T>> invokers, Invocation invocation) {
int length = invokers.size();
if (length == 1) {
return invokers.get(0);
}
if (length == 2) {
return chooseLowLoadInvoker(invokers.get(0), invokers.get(1), invocation);
}
int pos1 = ThreadLocalRandom.current().nextInt(length);
int pos2 = ThreadLocalRandom.current().nextInt(length - 1);
if (pos2 >= pos1) {
pos2 = pos2 + 1;
}
return chooseLowLoadInvoker(invokers.get(pos1), invokers.get(pos2), invocation);
}
private String getServiceKey(Invoker<?> invoker, Invocation invocation) {
String key = (String) invocation.getAttributes().get(invoker);
if (StringUtils.isNotEmpty(key)) {
return key;
}
key = buildServiceKey(invoker, invocation);
invocation.getAttributes().put(invoker, key);
return key;
}
private String buildServiceKey(Invoker<?> invoker, Invocation invocation) {
URL url = invoker.getUrl();
StringBuilder sb = new StringBuilder(128);
sb.append(url.getAddress()).append(":").append(invocation.getProtocolServiceKey());
return sb.toString();
}
private int getTimeout(Invoker<?> invoker, Invocation invocation) {
URL url = invoker.getUrl();
String methodName = RpcUtils.getMethodName(invocation);
return (int)
RpcUtils.getTimeout(url, methodName, RpcContext.getClientAttachment(), invocation, DEFAULT_TIMEOUT);
}
private <T> Invoker<T> chooseLowLoadInvoker(Invoker<T> invoker1, Invoker<T> invoker2, Invocation invocation) {
int weight1 = getWeight(invoker1, invocation);
int weight2 = getWeight(invoker2, invocation);
int timeout1 = getTimeout(invoker1, invocation);
int timeout2 = getTimeout(invoker2, invocation);
long load1 = Double.doubleToLongBits(
adaptiveMetrics.getLoad(getServiceKey(invoker1, invocation), weight1, timeout1));
long load2 = Double.doubleToLongBits(
adaptiveMetrics.getLoad(getServiceKey(invoker2, invocation), weight2, timeout2));
if (load1 == load2) {
// The sum of weights
int totalWeight = weight1 + weight2;
if (totalWeight > 0) {
int offset = ThreadLocalRandom.current().nextInt(totalWeight);
if (offset < weight1) {
return invoker1;
}
return invoker2;
}
return ThreadLocalRandom.current().nextInt(2) == 0 ? invoker1 : invoker2;
}
return load1 > load2 ? invoker2 : invoker1;
}
}

View File

@ -46,7 +46,7 @@ public class ConsistentHashLoadBalance extends AbstractLoadBalance {
*/ */
public static final String HASH_ARGUMENTS = "hash.arguments"; public static final String HASH_ARGUMENTS = "hash.arguments";
private final ConcurrentMap<String, ConsistentHashSelector<?>> selectors = new ConcurrentHashMap<>(); private final ConcurrentMap<String, ConsistentHashSelector<?>> selectors = new ConcurrentHashMap<String, ConsistentHashSelector<?>>();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
@ -74,7 +74,7 @@ public class ConsistentHashLoadBalance extends AbstractLoadBalance {
private final int[] argumentIndex; private final int[] argumentIndex;
ConsistentHashSelector(List<Invoker<T>> invokers, String methodName, int identityHashCode) { ConsistentHashSelector(List<Invoker<T>> invokers, String methodName, int identityHashCode) {
this.virtualInvokers = new TreeMap<>(); this.virtualInvokers = new TreeMap<Long, Invoker<T>>();
this.identityHashCode = identityHashCode; this.identityHashCode = identityHashCode;
URL url = invokers.get(0).getUrl(); URL url = invokers.get(0).getUrl();
this.replicaNumber = url.getMethodParameter(methodName, HASH_NODES, 160); this.replicaNumber = url.getMethodParameter(methodName, HASH_NODES, 160);
@ -96,8 +96,7 @@ public class ConsistentHashLoadBalance extends AbstractLoadBalance {
} }
public Invoker<T> select(Invocation invocation) { public Invoker<T> select(Invocation invocation) {
String key = toKey(RpcUtils.getArguments(invocation)); String key = toKey(invocation.getArguments());
byte[] digest = Bytes.getMD5(key); byte[] digest = Bytes.getMD5(key);
return selectForKey(hash(digest, 0)); return selectForKey(hash(digest, 0));
} }
@ -105,7 +104,7 @@ public class ConsistentHashLoadBalance extends AbstractLoadBalance {
private String toKey(Object[] args) { private String toKey(Object[] args) {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
for (int i : argumentIndex) { for (int i : argumentIndex) {
if (i >= 0 && args != null && i < args.length) { if (i >= 0 && i < args.length) {
buf.append(args[i]); buf.append(args[i]);
} }
} }
@ -122,10 +121,11 @@ public class ConsistentHashLoadBalance extends AbstractLoadBalance {
private long hash(byte[] digest, int number) { private long hash(byte[] digest, int number) {
return (((long) (digest[3 + number * 4] & 0xFF) << 24) return (((long) (digest[3 + number * 4] & 0xFF) << 24)
| ((long) (digest[2 + number * 4] & 0xFF) << 16) | ((long) (digest[2 + number * 4] & 0xFF) << 16)
| ((long) (digest[1 + number * 4] & 0xFF) << 8) | ((long) (digest[1 + number * 4] & 0xFF) << 8)
| (digest[number * 4] & 0xFF)) | (digest[number * 4] & 0xFF))
& 0xFFFFFFFFL; & 0xFFFFFFFFL;
} }
} }
} }

View File

@ -20,7 +20,6 @@ import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcStatus; import org.apache.dubbo.rpc.RpcStatus;
import org.apache.dubbo.rpc.support.RpcUtils;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@ -56,18 +55,17 @@ public class LeastActiveLoadBalance extends AbstractLoadBalance {
// Every least active invoker has the same weight value? // Every least active invoker has the same weight value?
boolean sameWeight = true; boolean sameWeight = true;
// Filter out all the least active invokers // Filter out all the least active invokers
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Invoker<T> invoker = invokers.get(i); Invoker<T> invoker = invokers.get(i);
// Get the active number of the invoker // Get the active number of the invoker
int active = RpcStatus.getStatus(invoker.getUrl(), RpcUtils.getMethodName(invocation)) int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive();
.getActive();
// Get the weight of the invoker's configuration. The default value is 100. // Get the weight of the invoker's configuration. The default value is 100.
int afterWarmup = getWeight(invoker, invocation); int afterWarmup = getWeight(invoker, invocation);
// save for later use // save for later use
weights[i] = afterWarmup; weights[i] = afterWarmup;
// If it is the first invoker or the active number of the invoker is less than the current least active // If it is the first invoker or the active number of the invoker is less than the current least active number
// number
if (leastActive == -1 || active < leastActive) { if (leastActive == -1 || active < leastActive) {
// Reset the active number of the current invoker to the least active number // Reset the active number of the current invoker to the least active number
leastActive = active; leastActive = active;
@ -99,7 +97,7 @@ public class LeastActiveLoadBalance extends AbstractLoadBalance {
return invokers.get(leastIndexes[0]); return invokers.get(leastIndexes[0]);
} }
if (!sameWeight && totalWeight > 0) { if (!sameWeight && totalWeight > 0) {
// If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on
// totalWeight. // totalWeight.
int offsetWeight = ThreadLocalRandom.current().nextInt(totalWeight); int offsetWeight = ThreadLocalRandom.current().nextInt(totalWeight);
// Return a invoker based on the random value. // Return a invoker based on the random value.

View File

@ -21,9 +21,7 @@ import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.cluster.ClusterInvoker; import org.apache.dubbo.rpc.cluster.ClusterInvoker;
import org.apache.dubbo.rpc.support.RpcUtils;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@ -45,9 +43,8 @@ public class RandomLoadBalance extends AbstractLoadBalance {
/** /**
* Select one invoker between a list using a random criteria * Select one invoker between a list using a random criteria
* * @param invokers List of possible invokers
* @param invokers List of possible invokers * @param url URL
* @param url URL
* @param invocation Invocation * @param invocation Invocation
* @param <T> * @param <T>
* @return The selected invoker * @return The selected invoker
@ -57,13 +54,13 @@ public class RandomLoadBalance extends AbstractLoadBalance {
// Number of invokers // Number of invokers
int length = invokers.size(); int length = invokers.size();
if (!needWeightLoadBalance(invokers, invocation)) { if (!needWeightLoadBalance(invokers,invocation)){
return invokers.get(ThreadLocalRandom.current().nextInt(length)); return invokers.get(ThreadLocalRandom.current().nextInt(length));
} }
// Every invoker has the same weight? // Every invoker has the same weight?
boolean sameWeight = true; boolean sameWeight = true;
// the maxWeight of every invoker, the minWeight = 0 or the maxWeight of the last invoker // the maxWeight of every invokers, the minWeight = 0 or the maxWeight of the last invoker
int[] weights = new int[length]; int[] weights = new int[length];
// The sum of weights // The sum of weights
int totalWeight = 0; int totalWeight = 0;
@ -78,27 +75,13 @@ public class RandomLoadBalance extends AbstractLoadBalance {
} }
} }
if (totalWeight > 0 && !sameWeight) { if (totalWeight > 0 && !sameWeight) {
// If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on totalWeight.
// totalWeight.
int offset = ThreadLocalRandom.current().nextInt(totalWeight); int offset = ThreadLocalRandom.current().nextInt(totalWeight);
// Return an invoker based on the random value. // Return a invoker based on the random value.
if (length <= 4) { for (int i = 0; i < length; i++) {
for (int i = 0; i < length; i++) { if (offset < weights[i]) {
if (offset < weights[i]) { return invokers.get(i);
return invokers.get(i);
}
} }
} else {
int i = Arrays.binarySearch(weights, offset);
if (i < 0) {
i = -i - 1;
} else {
while (weights[i + 1] == offset) {
i++;
}
i++;
}
return invokers.get(i);
} }
} }
// If all invokers have the same weight value or totalWeight=0, return evenly. // If all invokers have the same weight value or totalWeight=0, return evenly.
@ -106,7 +89,8 @@ public class RandomLoadBalance extends AbstractLoadBalance {
} }
private <T> boolean needWeightLoadBalance(List<Invoker<T>> invokers, Invocation invocation) { private <T> boolean needWeightLoadBalance(List<Invoker<T>> invokers, Invocation invocation) {
Invoker<T> invoker = invokers.get(0);
Invoker invoker = invokers.get(0);
URL invokerUrl = invoker.getUrl(); URL invokerUrl = invoker.getUrl();
if (invoker instanceof ClusterInvoker) { if (invoker instanceof ClusterInvoker) {
invokerUrl = ((ClusterInvoker<?>) invoker).getRegistryUrl(); invokerUrl = ((ClusterInvoker<?>) invoker).getRegistryUrl();
@ -115,15 +99,22 @@ public class RandomLoadBalance extends AbstractLoadBalance {
// Multiple registry scenario, load balance among multiple registries. // Multiple registry scenario, load balance among multiple registries.
if (REGISTRY_SERVICE_REFERENCE_PATH.equals(invokerUrl.getServiceInterface())) { if (REGISTRY_SERVICE_REFERENCE_PATH.equals(invokerUrl.getServiceInterface())) {
String weight = invokerUrl.getParameter(WEIGHT_KEY); String weight = invokerUrl.getParameter(WEIGHT_KEY);
return StringUtils.isNotEmpty(weight);
} else {
String weight = invokerUrl.getMethodParameter(RpcUtils.getMethodName(invocation), WEIGHT_KEY);
if (StringUtils.isNotEmpty(weight)) { if (StringUtils.isNotEmpty(weight)) {
return true; return true;
} else { }
} else {
String weight = invokerUrl.getMethodParameter(invocation.getMethodName(), WEIGHT_KEY);
if (StringUtils.isNotEmpty(weight)) {
return true;
}else {
String timeStamp = invoker.getUrl().getParameter(TIMESTAMP_KEY); String timeStamp = invoker.getUrl().getParameter(TIMESTAMP_KEY);
return StringUtils.isNotEmpty(timeStamp); if (StringUtils.isNotEmpty(timeStamp)) {
return true;
}
} }
} }
return false;
} }
} }

View File

@ -17,10 +17,8 @@
package org.apache.dubbo.rpc.cluster.loadbalance; package org.apache.dubbo.rpc.cluster.loadbalance;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.ConcurrentHashMapUtils;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.support.RpcUtils;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -37,12 +35,9 @@ public class RoundRobinLoadBalance extends AbstractLoadBalance {
private static final int RECYCLE_PERIOD = 60000; private static final int RECYCLE_PERIOD = 60000;
private final ConcurrentMap<String, ConcurrentMap<String, WeightedRoundRobin>> methodWeightMap =
new ConcurrentHashMap<>();
protected static class WeightedRoundRobin { protected static class WeightedRoundRobin {
private int weight; private int weight;
private final AtomicLong current = new AtomicLong(0); private AtomicLong current = new AtomicLong(0);
private long lastUpdate; private long lastUpdate;
public int getWeight() { public int getWeight() {
@ -71,6 +66,8 @@ public class RoundRobinLoadBalance extends AbstractLoadBalance {
} }
} }
private ConcurrentMap<String, ConcurrentMap<String, WeightedRoundRobin>> methodWeightMap = new ConcurrentHashMap<String, ConcurrentMap<String, WeightedRoundRobin>>();
/** /**
* get invoker addr list cached for specified invocation * get invoker addr list cached for specified invocation
* <p> * <p>
@ -81,7 +78,7 @@ public class RoundRobinLoadBalance extends AbstractLoadBalance {
* @return * @return
*/ */
protected <T> Collection<String> getInvokerAddrList(List<Invoker<T>> invokers, Invocation invocation) { protected <T> Collection<String> getInvokerAddrList(List<Invoker<T>> invokers, Invocation invocation) {
String key = invokers.get(0).getUrl().getServiceKey() + "." + RpcUtils.getMethodName(invocation); String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
Map<String, WeightedRoundRobin> map = methodWeightMap.get(key); Map<String, WeightedRoundRobin> map = methodWeightMap.get(key);
if (map != null) { if (map != null) {
return map.keySet(); return map.keySet();
@ -91,9 +88,8 @@ public class RoundRobinLoadBalance extends AbstractLoadBalance {
@Override @Override
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) { protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
String key = invokers.get(0).getUrl().getServiceKey() + "." + RpcUtils.getMethodName(invocation); String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
ConcurrentMap<String, WeightedRoundRobin> map = ConcurrentMap<String, WeightedRoundRobin> map = methodWeightMap.computeIfAbsent(key, k -> new ConcurrentHashMap<>());
ConcurrentHashMapUtils.computeIfAbsent(methodWeightMap, key, k -> new ConcurrentHashMap<>());
int totalWeight = 0; int totalWeight = 0;
long maxCurrent = Long.MIN_VALUE; long maxCurrent = Long.MIN_VALUE;
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
@ -102,14 +98,14 @@ public class RoundRobinLoadBalance extends AbstractLoadBalance {
for (Invoker<T> invoker : invokers) { for (Invoker<T> invoker : invokers) {
String identifyString = invoker.getUrl().toIdentityString(); String identifyString = invoker.getUrl().toIdentityString();
int weight = getWeight(invoker, invocation); int weight = getWeight(invoker, invocation);
WeightedRoundRobin weightedRoundRobin = ConcurrentHashMapUtils.computeIfAbsent(map, identifyString, k -> { WeightedRoundRobin weightedRoundRobin = map.computeIfAbsent(identifyString, k -> {
WeightedRoundRobin wrr = new WeightedRoundRobin(); WeightedRoundRobin wrr = new WeightedRoundRobin();
wrr.setWeight(weight); wrr.setWeight(weight);
return wrr; return wrr;
}); });
if (weight != weightedRoundRobin.getWeight()) { if (weight != weightedRoundRobin.getWeight()) {
// weight changed //weight changed
weightedRoundRobin.setWeight(weight); weightedRoundRobin.setWeight(weight);
} }
long cur = weightedRoundRobin.increaseCurrent(); long cur = weightedRoundRobin.increaseCurrent();
@ -131,4 +127,5 @@ public class RoundRobinLoadBalance extends AbstractLoadBalance {
// should not happen here // should not happen here
return invokers.get(0); return invokers.get(0);
} }
} }

View File

@ -18,14 +18,12 @@ package org.apache.dubbo.rpc.cluster.loadbalance;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository;
import org.apache.dubbo.common.utils.ConcurrentHashMapUtils;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcStatus; import org.apache.dubbo.rpc.RpcStatus;
import org.apache.dubbo.rpc.cluster.Constants; import org.apache.dubbo.rpc.cluster.Constants;
import org.apache.dubbo.rpc.model.ApplicationModel; import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ScopeModelAware; import org.apache.dubbo.rpc.model.ScopeModelAware;
import org.apache.dubbo.rpc.support.RpcUtils;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -49,9 +47,9 @@ public class ShortestResponseLoadBalance extends AbstractLoadBalance implements
private int slidePeriod = 30_000; private int slidePeriod = 30_000;
private final ConcurrentMap<RpcStatus, SlideWindowData> methodMap = new ConcurrentHashMap<>(); private ConcurrentMap<RpcStatus, SlideWindowData> methodMap = new ConcurrentHashMap<>();
private final AtomicBoolean onResetSlideWindow = new AtomicBoolean(false); private AtomicBoolean onResetSlideWindow = new AtomicBoolean(false);
private volatile long lastUpdateTime = System.currentTimeMillis(); private volatile long lastUpdateTime = System.currentTimeMillis();
@ -59,22 +57,16 @@ public class ShortestResponseLoadBalance extends AbstractLoadBalance implements
@Override @Override
public void setApplicationModel(ApplicationModel applicationModel) { public void setApplicationModel(ApplicationModel applicationModel) {
slidePeriod = applicationModel slidePeriod = applicationModel.getModelEnvironment().getConfiguration().getInt(Constants.SHORTEST_RESPONSE_SLIDE_PERIOD, 30_000);
.modelEnvironment() executorService = applicationModel.getFrameworkModel().getBeanFactory()
.getConfiguration() .getBean(FrameworkExecutorRepository.class).getSharedExecutor();
.getInt(Constants.SHORTEST_RESPONSE_SLIDE_PERIOD, 30_000);
executorService = applicationModel
.getFrameworkModel()
.getBeanFactory()
.getBean(FrameworkExecutorRepository.class)
.getSharedExecutor();
} }
protected static class SlideWindowData { protected static class SlideWindowData {
private long succeededOffset; private long succeededOffset;
private long succeededElapsedOffset; private long succeededElapsedOffset;
private final RpcStatus rpcStatus; private RpcStatus rpcStatus;
public SlideWindowData(RpcStatus rpcStatus) { public SlideWindowData(RpcStatus rpcStatus) {
this.rpcStatus = rpcStatus; this.rpcStatus = rpcStatus;
@ -123,12 +115,10 @@ public class ShortestResponseLoadBalance extends AbstractLoadBalance implements
// Filter out all the shortest response invokers // Filter out all the shortest response invokers
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Invoker<T> invoker = invokers.get(i); Invoker<T> invoker = invokers.get(i);
RpcStatus rpcStatus = RpcStatus.getStatus(invoker.getUrl(), RpcUtils.getMethodName(invocation)); RpcStatus rpcStatus = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName());
SlideWindowData slideWindowData = SlideWindowData slideWindowData = methodMap.computeIfAbsent(rpcStatus, SlideWindowData::new);
ConcurrentHashMapUtils.computeIfAbsent(methodMap, rpcStatus, SlideWindowData::new);
// Calculate the estimated response time from the product of active connections and succeeded average // Calculate the estimated response time from the product of active connections and succeeded average elapsed time.
// elapsed time.
long estimateResponse = slideWindowData.getEstimateResponse(); long estimateResponse = slideWindowData.getEstimateResponse();
int afterWarmup = getWeight(invoker, invocation); int afterWarmup = getWeight(invoker, invocation);
weights[i] = afterWarmup; weights[i] = afterWarmup;
@ -143,15 +133,16 @@ public class ShortestResponseLoadBalance extends AbstractLoadBalance implements
} else if (estimateResponse == shortestResponse) { } else if (estimateResponse == shortestResponse) {
shortestIndexes[shortestCount++] = i; shortestIndexes[shortestCount++] = i;
totalWeight += afterWarmup; totalWeight += afterWarmup;
if (sameWeight && i > 0 && afterWarmup != firstWeight) { if (sameWeight && i > 0
&& afterWarmup != firstWeight) {
sameWeight = false; sameWeight = false;
} }
} }
} }
if (System.currentTimeMillis() - lastUpdateTime > slidePeriod if (System.currentTimeMillis() - lastUpdateTime > slidePeriod
&& onResetSlideWindow.compareAndSet(false, true)) { && onResetSlideWindow.compareAndSet(false, true)) {
// reset slideWindowData in async way //reset slideWindowData in async way
executorService.execute(() -> { executorService.execute(() -> {
methodMap.values().forEach(SlideWindowData::reset); methodMap.values().forEach(SlideWindowData::reset);
lastUpdateTime = System.currentTimeMillis(); lastUpdateTime = System.currentTimeMillis();

View File

@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.merger; package org.apache.dubbo.rpc.cluster.merger;
import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.ArrayUtils;
@ -42,4 +43,5 @@ public class BooleanArrayMerger implements Merger<boolean[]> {
} }
return result; return result;
} }
} }

View File

@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.merger; package org.apache.dubbo.rpc.cluster.merger;
import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.ArrayUtils;
@ -42,4 +43,5 @@ public class ByteArrayMerger implements Merger<byte[]> {
} }
return result; return result;
} }
} }

View File

@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.merger; package org.apache.dubbo.rpc.cluster.merger;
import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.ArrayUtils;

View File

@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.merger; package org.apache.dubbo.rpc.cluster.merger;
import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.ArrayUtils;
@ -29,8 +30,7 @@ public class DoubleArrayMerger implements Merger<double[]> {
if (ArrayUtils.isEmpty(items)) { if (ArrayUtils.isEmpty(items)) {
return new double[0]; return new double[0];
} }
return Arrays.stream(items) return Arrays.stream(items).filter(Objects::nonNull)
.filter(Objects::nonNull)
.flatMapToDouble(Arrays::stream) .flatMapToDouble(Arrays::stream)
.toArray(); .toArray();
} }

View File

@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.merger; package org.apache.dubbo.rpc.cluster.merger;
import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.ArrayUtils;

View File

@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.merger; package org.apache.dubbo.rpc.cluster.merger;
import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.ArrayUtils;
@ -29,9 +30,9 @@ public class IntArrayMerger implements Merger<int[]> {
if (ArrayUtils.isEmpty(items)) { if (ArrayUtils.isEmpty(items)) {
return new int[0]; return new int[0];
} }
return Arrays.stream(items) return Arrays.stream(items).filter(Objects::nonNull)
.filter(Objects::nonNull)
.flatMapToInt(Arrays::stream) .flatMapToInt(Arrays::stream)
.toArray(); .toArray();
} }
} }

View File

@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.merger; package org.apache.dubbo.rpc.cluster.merger;
import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.ArrayUtils;
@ -33,9 +34,10 @@ public class ListMerger implements Merger<List<?>> {
if (ArrayUtils.isEmpty(items)) { if (ArrayUtils.isEmpty(items)) {
return Collections.emptyList(); return Collections.emptyList();
} }
return Stream.of(items) return Stream.of(items).filter(Objects::nonNull)
.filter(Objects::nonNull)
.flatMap(Collection::stream) .flatMap(Collection::stream)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
} }

View File

@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.merger; package org.apache.dubbo.rpc.cluster.merger;
import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.ArrayUtils;
@ -29,8 +30,7 @@ public class LongArrayMerger implements Merger<long[]> {
if (ArrayUtils.isEmpty(items)) { if (ArrayUtils.isEmpty(items)) {
return new long[0]; return new long[0];
} }
return Arrays.stream(items) return Arrays.stream(items).filter(Objects::nonNull)
.filter(Objects::nonNull)
.flatMapToLong(Arrays::stream) .flatMapToLong(Arrays::stream)
.toArray(); .toArray();
} }

View File

@ -32,8 +32,9 @@ public class MapMerger implements Merger<Map<?, ?>> {
if (ArrayUtils.isEmpty(items)) { if (ArrayUtils.isEmpty(items)) {
return Collections.emptyMap(); return Collections.emptyMap();
} }
Map<Object, Object> result = new HashMap<>(); Map<Object, Object> result = new HashMap<Object, Object>();
Stream.of(items).filter(Objects::nonNull).forEach(result::putAll); Stream.of(items).filter(Objects::nonNull).forEach(result::putAll);
return result; return result;
} }
} }

View File

@ -14,9 +14,10 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.merger; package org.apache.dubbo.rpc.cluster.merger;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.TypeUtils; import org.apache.dubbo.common.utils.TypeUtils;
@ -30,13 +31,11 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_LOAD_MERGER;
public class MergerFactory implements ScopeModelAware { public class MergerFactory implements ScopeModelAware {
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(MergerFactory.class); private static final Logger logger = LoggerFactory.getLogger(MergerFactory.class);
private ConcurrentMap<Class<?>, Merger<?>> MERGER_CACHE = new ConcurrentHashMap<>(); private ConcurrentMap<Class<?>, Merger<?>> MERGER_CACHE = new ConcurrentHashMap<Class<?>, Merger<?>>();
private ScopeModel scopeModel; private ScopeModel scopeModel;
@Override @Override
@ -68,17 +67,13 @@ public class MergerFactory implements ScopeModelAware {
} }
private void loadMergers() { private void loadMergers() {
Set<String> names = scopeModel.getExtensionLoader(Merger.class).getSupportedExtensions(); Set<String> names = scopeModel.getExtensionLoader(Merger.class)
.getSupportedExtensions();
for (String name : names) { for (String name : names) {
Merger m = scopeModel.getExtensionLoader(Merger.class).getExtension(name); Merger m = scopeModel.getExtensionLoader(Merger.class).getExtension(name);
Class<?> actualTypeArg = getActualTypeArgument(m.getClass()); Class<?> actualTypeArg = getActualTypeArgument(m.getClass());
if (actualTypeArg == null) { if (actualTypeArg == null) {
logger.warn( logger.warn("Failed to get actual type argument from merger " + m.getClass().getName());
CLUSTER_FAILED_LOAD_MERGER,
"load merger config failed",
"",
"Failed to get actual type argument from merger "
+ m.getClass().getName());
continue; continue;
} }
MERGER_CACHE.putIfAbsent(actualTypeArg, m); MERGER_CACHE.putIfAbsent(actualTypeArg, m);
@ -97,7 +92,7 @@ public class MergerFactory implements ScopeModelAware {
ParameterizedType mergerType; ParameterizedType mergerType;
for (Type it : interfaceTypes) { for (Type it : interfaceTypes) {
if (it instanceof ParameterizedType if (it instanceof ParameterizedType
&& (mergerType = ((ParameterizedType) it)).getRawType() == Merger.class) { && (mergerType = ((ParameterizedType) it)).getRawType() == Merger.class) {
Type typeArg = mergerType.getActualTypeArguments()[0]; Type typeArg = mergerType.getActualTypeArguments()[0];
return TypeUtils.getRawClass(typeArg); return TypeUtils.getRawClass(typeArg);
} }

View File

@ -32,7 +32,7 @@ public class SetMerger implements Merger<Set<?>> {
if (ArrayUtils.isEmpty(items)) { if (ArrayUtils.isEmpty(items)) {
return Collections.emptySet(); return Collections.emptySet();
} }
Set<Object> result = new HashSet<>(); Set<Object> result = new HashSet<Object>();
Stream.of(items).filter(Objects::nonNull).forEach(result::addAll); Stream.of(items).filter(Objects::nonNull).forEach(result::addAll);
return result; return result;
} }

View File

@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.merger; package org.apache.dubbo.rpc.cluster.merger;
import org.apache.dubbo.common.utils.ArrayUtils; import org.apache.dubbo.common.utils.ArrayUtils;

View File

@ -28,13 +28,12 @@ public abstract class AbstractRouter implements Router {
private GovernanceRuleRepository ruleRepository; private GovernanceRuleRepository ruleRepository;
public AbstractRouter(URL url) { public AbstractRouter(URL url) {
this.ruleRepository = url.getOrDefaultModuleModel() this.ruleRepository = url.getOrDefaultModuleModel().getExtensionLoader(GovernanceRuleRepository.class).getDefaultExtension();
.getExtensionLoader(GovernanceRuleRepository.class)
.getDefaultExtension();
this.url = url; this.url = url;
} }
public AbstractRouter() {} public AbstractRouter() {
}
@Override @Override
public URL getUrl() { public URL getUrl() {
@ -68,7 +67,8 @@ public abstract class AbstractRouter implements Router {
this.priority = priority; this.priority = priority;
} }
public GovernanceRuleRepository getRuleRepository() { public GovernanceRuleRepository getRuleRepository(){
return this.ruleRepository; return this.ruleRepository;
} }
} }

View File

@ -18,7 +18,6 @@ package org.apache.dubbo.rpc.cluster.router;
import java.util.Map; import java.util.Map;
import static org.apache.dubbo.rpc.cluster.Constants.CONFIG_VERSION_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.DYNAMIC_KEY; import static org.apache.dubbo.rpc.cluster.Constants.DYNAMIC_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.ENABLED_KEY; import static org.apache.dubbo.rpc.cluster.Constants.ENABLED_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY; import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;
@ -41,7 +40,6 @@ public abstract class AbstractRouterRule {
private int priority; private int priority;
private boolean dynamic = false; private boolean dynamic = false;
private String version;
private String scope; private String scope;
private String key; private String key;
@ -80,7 +78,6 @@ public abstract class AbstractRouterRule {
setScope((String) map.get(SCOPE_KEY)); setScope((String) map.get(SCOPE_KEY));
setKey((String) map.get(KEY_KEY)); setKey((String) map.get(KEY_KEY));
setVersion((String) map.get(CONFIG_VERSION_KEY));
} }
public String getRawRule() { public String getRawRule() {
@ -154,12 +151,4 @@ public abstract class AbstractRouterRule {
public void setKey(String key) { public void setKey(String key) {
this.key = key; this.key = key;
} }
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
} }

View File

@ -34,7 +34,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
public class RouterSnapshotFilter implements ClusterFilter, BaseFilter.Listener { public class RouterSnapshotFilter implements ClusterFilter, BaseFilter.Listener {
private final RouterSnapshotSwitcher switcher; private final RouterSnapshotSwitcher switcher;
private static final Logger logger = LoggerFactory.getLogger(RouterSnapshotFilter.class); private final static Logger logger = LoggerFactory.getLogger(RouterSnapshotFilter.class);
public RouterSnapshotFilter(FrameworkModel frameworkModel) { public RouterSnapshotFilter(FrameworkModel frameworkModel) {
this.switcher = frameworkModel.getBeanFactory().getBean(RouterSnapshotSwitcher.class); this.switcher = frameworkModel.getBeanFactory().getBean(RouterSnapshotSwitcher.class);

View File

@ -114,55 +114,43 @@ public class RouterSnapshotNode<T> {
public String toString(int level) { public String toString(int level) {
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
stringBuilder stringBuilder.append("[ ")
.append("[ ") .append(name)
.append(name) .append(' ')
.append(' ') .append("(Input: ").append(beforeSize).append(") ")
.append("(Input: ") .append("(Current Node Output: ").append(nodeOutputSize).append(") ")
.append(beforeSize) .append("(Chain Node Output: ").append(chainOutputSize).append(')')
.append(") ") .append(routerMessage == null ? "" : " Router message: ")
.append("(Current Node Output: ") .append(routerMessage == null ? "" : routerMessage)
.append(nodeOutputSize) .append(" ] ");
.append(") ")
.append("(Chain Node Output: ")
.append(chainOutputSize)
.append(')')
.append(routerMessage == null ? "" : " Router message: ")
.append(routerMessage == null ? "" : routerMessage)
.append(" ] ");
if (level == 1) { if (level == 1) {
stringBuilder stringBuilder.append("Input: ")
.append("Input: ") .append(CollectionUtils.isEmpty(inputInvokers) ? "Empty" :
.append( inputInvokers.subList(0, Math.min(5, inputInvokers.size()))
CollectionUtils.isEmpty(inputInvokers) .stream()
? "Empty" .map(Invoker::getUrl)
: inputInvokers.subList(0, Math.min(5, inputInvokers.size())).stream() .map(URL::getAddress)
.map(Invoker::getUrl) .collect(Collectors.joining(",")))
.map(URL::getAddress) .append(" -> ");
.collect(Collectors.joining(",")))
.append(" -> ");
stringBuilder stringBuilder.append("Chain Node Output: ")
.append("Chain Node Output: ") .append(CollectionUtils.isEmpty(chainOutputInvokers) ? "Empty" :
.append( chainOutputInvokers.subList(0, Math.min(5, chainOutputInvokers.size()))
CollectionUtils.isEmpty(chainOutputInvokers) .stream()
? "Empty" .map(Invoker::getUrl)
: chainOutputInvokers.subList(0, Math.min(5, chainOutputInvokers.size())).stream() .map(URL::getAddress)
.map(Invoker::getUrl) .collect(Collectors.joining(",")));
.map(URL::getAddress)
.collect(Collectors.joining(",")));
} else { } else {
stringBuilder stringBuilder.append("Current Node Output: ")
.append("Current Node Output: ") .append(CollectionUtils.isEmpty(nodeOutputInvokers) ? "Empty" :
.append( nodeOutputInvokers.subList(0, Math.min(5, nodeOutputInvokers.size()))
CollectionUtils.isEmpty(nodeOutputInvokers) .stream()
? "Empty" .map(Invoker::getUrl)
: nodeOutputInvokers.subList(0, Math.min(5, nodeOutputInvokers.size())).stream() .map(URL::getAddress)
.map(Invoker::getUrl) .collect(Collectors.joining(",")));
.map(URL::getAddress)
.collect(Collectors.joining(",")));
} }
if (nodeOutputInvokers != null && nodeOutputInvokers.size() > 5) { if (nodeOutputInvokers != null && nodeOutputInvokers.size() > 5) {
stringBuilder.append("..."); stringBuilder.append("...");
} }

View File

@ -26,7 +26,7 @@ public class RouterSnapshotSwitcher {
private volatile boolean enable; private volatile boolean enable;
private final Set<String> enabledService = new ConcurrentHashSet<>(); private final Set<String> enabledService = new ConcurrentHashSet<>();
private static final int MAX_LENGTH = 1 << 5; // 2 ^ 5 = 31 private final static int MAX_LENGTH = 1 << 5; // 2 ^ 5 = 31
private final AtomicInteger offset = new AtomicInteger(0); private final AtomicInteger offset = new AtomicInteger(0);
private volatile String[] recentSnapshot = new String[MAX_LENGTH]; private volatile String[] recentSnapshot = new String[MAX_LENGTH];

View File

@ -17,75 +17,62 @@
package org.apache.dubbo.rpc.cluster.router.condition; package org.apache.dubbo.rpc.cluster.router.condition;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.Holder; import org.apache.dubbo.common.utils.Holder;
import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Constants;
import org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode; import org.apache.dubbo.rpc.cluster.router.RouterSnapshotNode;
import org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcher; import org.apache.dubbo.rpc.cluster.router.condition.config.AppStateRouter;
import org.apache.dubbo.rpc.cluster.router.condition.matcher.ConditionMatcherFactory;
import org.apache.dubbo.rpc.cluster.router.condition.matcher.pattern.ValuePattern;
import org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter; import org.apache.dubbo.rpc.cluster.router.state.AbstractStateRouter;
import org.apache.dubbo.rpc.cluster.router.state.BitList; import org.apache.dubbo.rpc.cluster.router.state.BitList;
import java.text.ParseException; import java.text.ParseException;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY; import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY; import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.CLUSTER_FAILED_EXEC_CONDITION_ROUTER; import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.ADDRESS_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY; import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY; import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY; import static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;
/** /**
* Condition Router directs traffics matching the 'when condition' to a particular address subset determined by the 'then condition'. * ConditionRouter
* One typical condition rule is like below, with * It supports the conditional routing configured by "override://", in 2.6.x,
* 1. the 'when condition' on the left side of '=>' contains matching rule like 'method=sayHello' and 'method=sayHi' * refer to https://dubbo.apache.org/en/docs/v2.7/user/examples/routing-rule/ .
* 2. the 'then condition' on the right side of '=>' contains matching rule like 'region=hangzhou' and 'address=*:20881' * For 2.7.x and later, please refer to {@link org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouter}
* <p> * and {@link AppStateRouter}
* By default, condition router support matching rules like 'foo=bar', 'foo=bar*', 'arguments[0]=bar', 'attachments[foo]=bar', 'attachments[foo]=1~100', etc. * refer to https://dubbo.apache.org/zh/docs/v2.7/user/examples/routing-rule/ .
* It's also very easy to add customized matching rules by extending {@link ConditionMatcherFactory}
* and {@link ValuePattern}
* <p>
* ---
* scope: service
* force: true
* runtime: true
* enabled: true
* key: org.apache.dubbo.samples.governance.api.DemoService
* conditions:
* - method=sayHello => region=hangzhou
* - method=sayHi => address=*:20881
* ...
*/ */
public class ConditionStateRouter<T> extends AbstractStateRouter<T> { public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
public static final String NAME = "condition"; public static final String NAME = "condition";
private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(AbstractStateRouter.class); private static final Logger logger = LoggerFactory.getLogger(ConditionStateRouter.class);
protected static final Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)"); protected static final Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)");
protected Map<String, ConditionMatcher> whenCondition; protected static Pattern ARGUMENTS_PATTERN = Pattern.compile("arguments\\[([0-9]+)\\]");
protected Map<String, ConditionMatcher> thenCondition; protected Map<String, MatchPair> whenCondition;
protected List<ConditionMatcherFactory> matcherFactories; protected Map<String, MatchPair> thenCondition;
private final boolean enabled; private boolean enabled;
public ConditionStateRouter(URL url, String rule, boolean force, boolean enabled) { public ConditionStateRouter(URL url, String rule, boolean force, boolean enabled) {
super(url); super(url);
this.setForce(force); this.setForce(force);
this.enabled = enabled; this.enabled = enabled;
matcherFactories =
moduleModel.getExtensionLoader(ConditionMatcherFactory.class).getActivateExtensions();
if (enabled) { if (enabled) {
this.init(rule); this.init(rule);
} }
@ -95,8 +82,6 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
super(url); super(url);
this.setUrl(url); this.setUrl(url);
this.setForce(url.getParameter(FORCE_KEY, false)); this.setForce(url.getParameter(FORCE_KEY, false));
matcherFactories =
moduleModel.getExtensionLoader(ConditionMatcherFactory.class).getActivateExtensions();
this.enabled = url.getParameter(ENABLED_KEY, true); this.enabled = url.getParameter(ENABLED_KEY, true);
if (enabled) { if (enabled) {
init(url.getParameterAndDecoded(RULE_KEY)); init(url.getParameterAndDecoded(RULE_KEY));
@ -112,10 +97,8 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
int i = rule.indexOf("=>"); int i = rule.indexOf("=>");
String whenRule = i < 0 ? null : rule.substring(0, i).trim(); String whenRule = i < 0 ? null : rule.substring(0, i).trim();
String thenRule = i < 0 ? rule.trim() : rule.substring(i + 2).trim(); String thenRule = i < 0 ? rule.trim() : rule.substring(i + 2).trim();
Map<String, ConditionMatcher> when = Map<String, MatchPair> when = StringUtils.isBlank(whenRule) || "true".equals(whenRule) ? new HashMap<String, MatchPair>() : parseRule(whenRule);
StringUtils.isBlank(whenRule) || "true".equals(whenRule) ? new HashMap<>() : parseRule(whenRule); Map<String, MatchPair> then = StringUtils.isBlank(thenRule) || "false".equals(thenRule) ? null : parseRule(thenRule);
Map<String, ConditionMatcher> then =
StringUtils.isBlank(thenRule) || "false".equals(thenRule) ? null : parseRule(thenRule);
// NOTE: It should be determined on the business level whether the `When condition` can be empty or not. // NOTE: It should be determined on the business level whether the `When condition` can be empty or not.
this.whenCondition = when; this.whenCondition = when;
this.thenCondition = then; this.thenCondition = then;
@ -124,13 +107,14 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
} }
} }
private Map<String, ConditionMatcher> parseRule(String rule) throws ParseException { private static Map<String, MatchPair> parseRule(String rule)
Map<String, ConditionMatcher> condition = new HashMap<>(); throws ParseException {
Map<String, MatchPair> condition = new HashMap<String, MatchPair>();
if (StringUtils.isBlank(rule)) { if (StringUtils.isBlank(rule)) {
return condition; return condition;
} }
// Key-Value pair, stores both match and mismatch conditions // Key-Value pair, stores both match and mismatch conditions
ConditionMatcher matcherPair = null; MatchPair pair = null;
// Multiple values // Multiple values
Set<String> values = null; Set<String> values = null;
final Matcher matcher = ROUTE_PATTERN.matcher(rule); final Matcher matcher = ROUTE_PATTERN.matcher(rule);
@ -139,77 +123,64 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
String content = matcher.group(2); String content = matcher.group(2);
// Start part of the condition expression. // Start part of the condition expression.
if (StringUtils.isEmpty(separator)) { if (StringUtils.isEmpty(separator)) {
matcherPair = this.getMatcher(content); pair = new MatchPair();
condition.put(content, matcherPair); condition.put(content, pair);
} }
// The KV part of the condition expression // The KV part of the condition expression
else if ("&".equals(separator)) { else if ("&".equals(separator)) {
if (condition.get(content) == null) { if (condition.get(content) == null) {
matcherPair = this.getMatcher(content); pair = new MatchPair();
condition.put(content, matcherPair); condition.put(content, pair);
} else { } else {
matcherPair = condition.get(content); pair = condition.get(content);
} }
} }
// The Value in the KV part. // The Value in the KV part.
else if ("=".equals(separator)) { else if ("=".equals(separator)) {
if (matcherPair == null) { if (pair == null) {
throw new ParseException( throw new ParseException("Illegal route rule \""
"Illegal route rule \"" + rule + "\", The error char '" + separator
+ rule + "\", The error char '" + separator + "' at index " + matcher.start() + " before \""
+ "' at index " + matcher.start() + " before \"" + content + "\".", matcher.start());
+ content + "\".",
matcher.start());
} }
values = matcherPair.getMatches(); values = pair.matches;
values.add(content); values.add(content);
} }
// The Value in the KV part. // The Value in the KV part.
else if ("!=".equals(separator)) { else if ("!=".equals(separator)) {
if (matcherPair == null) { if (pair == null) {
throw new ParseException( throw new ParseException("Illegal route rule \""
"Illegal route rule \"" + rule + "\", The error char '" + separator
+ rule + "\", The error char '" + separator + "' at index " + matcher.start() + " before \""
+ "' at index " + matcher.start() + " before \"" + content + "\".", matcher.start());
+ content + "\".",
matcher.start());
} }
values = matcherPair.getMismatches(); values = pair.mismatches;
values.add(content); values.add(content);
} }
// The Value in the KV part, if Value have more than one items. // The Value in the KV part, if Value have more than one items.
else if (",".equals(separator)) { // Should be separated by ',' else if (",".equals(separator)) { // Should be separated by ','
if (values == null || values.isEmpty()) { if (values == null || values.isEmpty()) {
throw new ParseException( throw new ParseException("Illegal route rule \""
"Illegal route rule \"" + rule + "\", The error char '" + separator
+ rule + "\", The error char '" + separator + "' at index " + matcher.start() + " before \""
+ "' at index " + matcher.start() + " before \"" + content + "\".", matcher.start());
+ content + "\".",
matcher.start());
} }
values.add(content); values.add(content);
} else { } else {
throw new ParseException( throw new ParseException("Illegal route rule \"" + rule
"Illegal route rule \"" + rule + "\", The error char '" + separator + "' at index "
+ "\", The error char '" + separator + "' at index " + matcher.start() + " before \"" + content + "\".", matcher.start());
+ matcher.start() + " before \"" + content + "\".",
matcher.start());
} }
} }
return condition; return condition;
} }
@Override @Override
protected BitList<Invoker<T>> doRoute( protected BitList<Invoker<T>> doRoute(BitList<Invoker<T>> invokers, URL url, Invocation invocation,
BitList<Invoker<T>> invokers, boolean needToPrintMessage, Holder<RouterSnapshotNode<T>> nodeHolder,
URL url, Holder<String> messageHolder) throws RpcException {
Invocation invocation,
boolean needToPrintMessage,
Holder<RouterSnapshotNode<T>> nodeHolder,
Holder<String> messageHolder)
throws RpcException {
if (!enabled) { if (!enabled) {
if (needToPrintMessage) { if (needToPrintMessage) {
messageHolder.set("Directly return. Reason: ConditionRouter disabled."); messageHolder.set("Directly return. Reason: ConditionRouter disabled.");
@ -231,12 +202,7 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
return invokers; return invokers;
} }
if (thenCondition == null) { if (thenCondition == null) {
logger.warn( logger.warn("The current consumer in the service blacklist. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey());
CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY,
"condition state router thenCondition is empty",
"",
"The current consumer in the service blocklist. consumer: " + NetUtils.getLocalHost()
+ ", service: " + url.getServiceKey());
if (needToPrintMessage) { if (needToPrintMessage) {
messageHolder.set("Empty return. Reason: ThenCondition is empty."); messageHolder.set("Empty return. Reason: ThenCondition is empty.");
} }
@ -251,26 +217,15 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
} }
return result; return result;
} else if (this.isForce()) { } else if (this.isForce()) {
logger.warn( logger.warn("The route result is empty and force execute. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey() + ", router: " + url.getParameterAndDecoded(RULE_KEY));
CLUSTER_CONDITIONAL_ROUTE_LIST_EMPTY,
"execute condition state router result list is empty. and force=true",
"",
"The route result is empty and force execute. consumer: " + NetUtils.getLocalHost()
+ ", service: " + url.getServiceKey() + ", router: "
+ url.getParameterAndDecoded(RULE_KEY));
if (needToPrintMessage) { if (needToPrintMessage) {
messageHolder.set("Empty return. Reason: Empty result from condition and condition is force."); messageHolder.set("Empty return. Reason: Empty result from condition and condition is force.");
} }
return result; return result;
} }
} catch (Throwable t) { } catch (Throwable t) {
logger.error( logger.error("Failed to execute condition router rule: " + getUrl() + ", invokers: " + invokers + ", cause: " + t.getMessage(), t);
CLUSTER_FAILED_EXEC_CONDITION_ROUTER,
"execute condition state router exception",
"",
"Failed to execute condition router rule: " + getUrl() + ", invokers: " + invokers + ", cause: "
+ t.getMessage(),
t);
} }
if (needToPrintMessage) { if (needToPrintMessage) {
messageHolder.set("Directly return. Reason: Error occurred ( or result is empty )."); messageHolder.set("Directly return. Reason: Error occurred ( or result is empty ).");
@ -281,51 +236,139 @@ public class ConditionStateRouter<T> extends AbstractStateRouter<T> {
@Override @Override
public boolean isRuntime() { public boolean isRuntime() {
// We always return true for previously defined Router, that is, old Router doesn't support cache anymore. // We always return true for previously defined Router, that is, old Router doesn't support cache anymore.
// return true; // return true;
return this.getUrl().getParameter(RUNTIME_KEY, false); return this.getUrl().getParameter(RUNTIME_KEY, false);
} }
private ConditionMatcher getMatcher(String key) {
for (ConditionMatcherFactory factory : matcherFactories) {
if (factory.shouldMatch(key)) {
return factory.createMatcher(key, moduleModel);
}
}
return moduleModel
.getExtensionLoader(ConditionMatcherFactory.class)
.getExtension("param")
.createMatcher(key, moduleModel);
}
boolean matchWhen(URL url, Invocation invocation) { boolean matchWhen(URL url, Invocation invocation) {
if (CollectionUtils.isEmptyMap(whenCondition)) { return CollectionUtils.isEmptyMap(whenCondition) || matchCondition(whenCondition, url, null, invocation);
return true;
}
return doMatch(url, null, invocation, whenCondition, true);
} }
private boolean matchThen(URL url, URL param) { private boolean matchThen(URL url, URL param) {
if (CollectionUtils.isEmptyMap(thenCondition)) { return CollectionUtils.isNotEmptyMap(thenCondition) && matchCondition(thenCondition, url, param, null);
return false;
}
return doMatch(url, param, null, thenCondition, false);
} }
private boolean doMatch( private boolean matchCondition(Map<String, MatchPair> condition, URL url, URL param, Invocation invocation) {
URL url, Map<String, String> sample = url.toMap();
URL param, boolean result = false;
Invocation invocation, for (Map.Entry<String, MatchPair> matchPair : condition.entrySet()) {
Map<String, ConditionMatcher> conditions, String key = matchPair.getKey();
boolean isWhenCondition) {
Map<String, String> sample = url.toOriginalMap(); if (key.startsWith(Constants.ARGUMENTS)) {
for (Map.Entry<String, ConditionMatcher> entry : conditions.entrySet()) { if (!matchArguments(matchPair, invocation)) {
ConditionMatcher matchPair = entry.getValue(); return false;
if (!matchPair.isMatch(sample, param, invocation, isWhenCondition)) { } else {
return false; result = true;
continue;
}
}
String sampleValue;
//get real invoked method name from invocation
if (invocation != null && (METHOD_KEY.equals(key) || METHODS_KEY.equals(key))) {
sampleValue = invocation.getMethodName();
} else if (ADDRESS_KEY.equals(key)) {
sampleValue = url.getAddress();
} else if (HOST_KEY.equals(key)) {
sampleValue = url.getHost();
} else {
sampleValue = sample.get(key);
}
if (sampleValue != null) {
if (!matchPair.getValue().isMatch(sampleValue, param)) {
return false;
} else {
result = true;
}
} else {
//not pass the condition
if (!matchPair.getValue().matches.isEmpty()) {
return false;
} else {
result = true;
}
} }
} }
return true; return result;
}
/**
* analysis the arguments in the rule.
* Examples would be like this:
* "arguments[0]=1", whenCondition is that the first argument is equal to '1'.
* "arguments[1]=a", whenCondition is that the second argument is equal to 'a'.
* @param matchPair
* @param invocation
* @return
*/
public boolean matchArguments(Map.Entry<String, MatchPair> matchPair, Invocation invocation) {
try {
// split the rule
String key = matchPair.getKey();
String[] expressArray = key.split("\\.");
String argumentExpress = expressArray[0];
final Matcher matcher = ARGUMENTS_PATTERN.matcher(argumentExpress);
if (!matcher.find()) {
return false;
}
//extract the argument index
int index = Integer.parseInt(matcher.group(1));
if (index < 0 || index > invocation.getArguments().length) {
return false;
}
//extract the argument value
Object object = invocation.getArguments()[index];
if (matchPair.getValue().isMatch(String.valueOf(object), null)) {
return true;
}
} catch (Exception e) {
logger.warn("Arguments match failed, matchPair[]" + matchPair + "] invocation[" + invocation + "]", e);
}
return false;
}
protected static final class MatchPair {
final Set<String> matches = new HashSet<String>();
final Set<String> mismatches = new HashSet<String>();
private boolean isMatch(String value, URL param) {
if (!matches.isEmpty() && mismatches.isEmpty()) {
for (String match : matches) {
if (UrlUtils.isMatchGlobPattern(match, value, param)) {
return true;
}
}
return false;
}
if (!mismatches.isEmpty() && matches.isEmpty()) {
for (String mismatch : mismatches) {
if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
return false;
}
}
return true;
}
if (!matches.isEmpty() && !mismatches.isEmpty()) {
//when both mismatches and matches contain the same value, then using mismatches first
for (String mismatch : mismatches) {
if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
return false;
}
}
for (String match : matches) {
if (UrlUtils.isMatchGlobPattern(match, value, param)) {
return true;
}
}
return false;
}
return false;
}
} }
} }

View File

@ -30,6 +30,6 @@ public class ConditionStateRouterFactory extends CacheableStateRouterFactory {
@Override @Override
protected <T> StateRouter<T> createRouter(Class<T> interfaceClass, URL url) { protected <T> StateRouter<T> createRouter(Class<T> interfaceClass, URL url) {
return new ConditionStateRouter<>(url); return new ConditionStateRouter<T>(url);
} }
} }

Some files were not shown because too many files have changed in this diff Show More