Skip to content

Commit c9e8ca8

Browse files
committed
feat!(retries): Retries will be treated different when no dlq, now we support # wildcard on handlers
1 parent e118abb commit c9e8ca8

File tree

18 files changed

+250
-119
lines changed

18 files changed

+250
-119
lines changed

.github/workflows/main.yml

+24-58
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,44 @@
11
name: 'reactive-commons-ci-cd'
2-
32
on:
43
push:
54
branches:
65
- master
7-
86
pull_request:
97
branches:
108
- master
11-
12-
release:
13-
types: [ created ]
14-
159
jobs:
1610
build:
17-
if: github.event_name != 'release'
11+
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
12+
permissions:
13+
contents: write
14+
issues: write
15+
pull-requests: write
1816
runs-on: ubuntu-latest
1917
steps:
20-
- uses: actions/checkout@v3
18+
- uses: actions/checkout@v4
19+
- name: Verify Conventional Commits
20+
uses: amannn/action-semantic-pull-request@v5
21+
if: github.event_name == 'pull_request' || github.event_name == 'pull_request_target'
22+
env:
23+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
24+
- name: Set up NodeJS
25+
if: github.ref == 'refs/heads/master'
26+
uses: actions/setup-node@v4
2127
with:
22-
fetch-depth: 0
28+
node-version-file: '.nvmrc'
29+
- name: Set up Semantic Release
30+
if: github.ref == 'refs/heads/master'
31+
run: npm -g install @semantic-release/git [email protected]
32+
- name: Semantic Release
33+
if: github.ref == 'refs/heads/master'
34+
35+
env:
36+
GITHUB_TOKEN: ${{ secrets.PA_TOKEN }}
2337
- name: Set up JDK 17
2438
uses: actions/setup-java@v3
2539
with:
2640
distribution: temurin
2741
java-version: 17
28-
- name: Grant execute permission for gradlew
29-
run: chmod +x gradlew
3042
- name: Execute build test jacocoTestReport and sonar analysis
3143
if: endsWith(github.REF, '/master') == true
3244
env:
@@ -38,50 +50,4 @@ jobs:
3850
env:
3951
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4052
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
41-
run: ./gradlew build test jacocoTestReport --refresh-dependencies --no-daemon --continue -Denv.ci=true
42-
43-
release:
44-
if: github.event_name == 'release'
45-
runs-on: ubuntu-latest
46-
steps:
47-
- uses: actions/checkout@v3
48-
- name: Set up JDK 17
49-
uses: actions/setup-java@v3
50-
with:
51-
distribution: temurin
52-
java-version: 17
53-
- name: Grant execute permission for gradlew
54-
run: chmod +x gradlew
55-
# - name: Execute jacocoTestReport
56-
# run: ./gradlew test jacocoTestReport && cp build/reports/jacoco/report.xml jacoco.xml || echo "Code coverage failed"
57-
- name: Build with Gradle
58-
run: ./gradlew build --refresh-dependencies --no-daemon --continue -Denv.ci=true
59-
- name: Prepare gpg key
60-
run: |
61-
echo "${{secrets.SIGNING_KEY_FILE}}" | base64 -d > ~/.gradle/secring.gpg
62-
- name: Publish Libraries
63-
run: ./gradlew publish -Psigning.keyId=${{ secrets.SIGNING_KEY_ID }} -Psigning.password=${{ secrets.SIGNING_KEY_PASSWORD }} -Psigning.secretKeyRingFile=$(echo ~/.gradle/secring.gpg) -Denv.ci=true
64-
env:
65-
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
66-
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
67-
- name: Generate Changelog
68-
uses: heinrichreimer/[email protected]
69-
with:
70-
token: ${{ secrets.GITHUB_TOKEN }}
71-
pullRequests: true
72-
prWoLabels: true
73-
issues: true
74-
issuesWoLabels: true
75-
stripGeneratorNotice: true
76-
- name: Push Changelog
77-
uses: github-actions-x/[email protected]
78-
with:
79-
github-token: ${{ secrets.GITHUB_TOKEN }}
80-
push-branch: 'master'
81-
commit-message: 'Automatic docs and changelog generation'
82-
force-add: 'true'
83-
files: CHANGELOG.md
84-
name: ${{ github.actor }}
85-
email: ${{ github.actor }}@users.noreply.github.com
86-
# - name: Push codeCoverage to Codecov
87-
# run: bash <(curl -s https://codecov.io/bash)
53+
run: ./gradlew build test jacocoTestReport --refresh-dependencies --no-daemon --continue -Denv.ci=true

.github/workflows/release.yml

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: release
2+
on:
3+
release:
4+
types: [ released ]
5+
jobs:
6+
release:
7+
runs-on: ubuntu-latest
8+
steps:
9+
- uses: actions/checkout@v4
10+
- name: Set env
11+
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/v}" >> $GITHUB_ENV
12+
- name: Upgrade Gradle.properties
13+
run: sed -i 's/version=.*/version=${{ env.RELEASE_VERSION }}/g' gradle.properties
14+
- name: Generate Changelog
15+
uses: heinrichreimer/[email protected]
16+
with:
17+
token: ${{ secrets.GITHUB_TOKEN }}
18+
pullRequests: true
19+
prWoLabels: true
20+
issues: true
21+
issuesWoLabels: true
22+
stripGeneratorNotice: true
23+
- name: Push Changelog
24+
uses: github-actions-x/[email protected]
25+
with:
26+
github-token: ${{ secrets.GITHUB_TOKEN }}
27+
push-branch: 'master'
28+
commit-message: 'Automatic docs and changelog generation [skip ci]'
29+
force-add: 'true'
30+
files: CHANGELOG.md
31+
name: ${{ github.actor }}
32+
email: ${{ github.actor }}@users.noreply.github.com
33+
- name: Set up JDK 17
34+
uses: actions/setup-java@v3
35+
with:
36+
distribution: temurin
37+
java-version: 17
38+
- name: Build with Gradle
39+
run: ./gradlew build --refresh-dependencies --no-daemon --continue -Denv.ci=true
40+
- name: Prepare gpg key
41+
run: |
42+
echo "${{secrets.SIGNING_KEY_FILE}}" | base64 -d > ~/.gradle/secring.gpg
43+
- name: Publish Libraries
44+
run: ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository -Psigning.keyId=${{ secrets.SIGNING_KEY_ID }} -Psigning.password=${{ secrets.SIGNING_KEY_PASSWORD }} -Psigning.secretKeyRingFile=$(echo ~/.gradle/secring.gpg)
45+
env:
46+
ORG_GRADLE_PROJECT_sonatypeUsername: ${{ secrets.MAVEN_USERNAME }}
47+
ORG_GRADLE_PROJECT_sonatypePassword: ${{ secrets.MAVEN_PASSWORD }}

.nvmrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v20.11.0

.releaserc

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"branches": ["master"],
3+
"plugins": [
4+
"@semantic-release/commit-analyzer",
5+
"@semantic-release/release-notes-generator",
6+
["@semantic-release/git",
7+
{
8+
"assets": [ { "path": "build/**/*", "label": "Compiled files" }],
9+
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
10+
}
11+
],
12+
"@semantic-release/github"
13+
]
14+
}
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
package org.reactivecommons.async.commons.utils.matcher;
22

3-
import org.apache.commons.io.FilenameUtils;
4-
3+
import java.util.List;
54
import java.util.Set;
5+
import java.util.regex.Pattern;
6+
import java.util.stream.Collectors;
67

78
public class KeyMatcher implements Matcher {
89

910
public static final String SEPARATOR_REGEX = "\\.";
10-
public static final String WILDCARD_CHAR = "*";
11+
public static final String SINGLE_WORD_WILDCARD = "*";
12+
public static final String MULTIPLE_WORD_WILDCARD = "#";
1113

1214
@Override
1315
public String match(Set<String> sources, String target) {
@@ -16,31 +18,89 @@ public String match(Set<String> sources, String target) {
1618
matchMissingKey(sources, target);
1719
}
1820

19-
private String matchMissingKey(Set<String> names, String target) {
21+
public static String matchMissingKey(Set<String> names, String target) {
2022
return names.stream()
21-
.filter(name -> name.contains(WILDCARD_CHAR))
22-
.sorted(this::compare)
23-
.filter(name -> FilenameUtils.wildcardMatch(target, name))
24-
.findFirst()
23+
.filter(name -> matches(target, name))
24+
.min(KeyMatcher::compare)
2525
.orElse(target);
2626
}
2727

28-
private int compare(String firstExpression, String secondExpression) {
28+
public static void main(String[] args) {
29+
Set<String> names = Set.of(
30+
"*.*.*",
31+
"*.#.*",
32+
"prefix.*.*",
33+
"prefix.*.#",
34+
"*.middle.*",
35+
"*.*.suffix",
36+
"*.middle.#",
37+
"*.middle.suffix",
38+
"#.middle.suffix",
39+
"prefix.*.suffix",
40+
"prefix.#.suffix",
41+
"prefix.middle.*",
42+
"prefix.middle.#",
43+
"prefix.middle.suffix",
44+
"prefix.other.other",
45+
"other.middle.other",
46+
"other.other.suffix",
47+
"other.other.other",
48+
"in.depend.ent");
49+
String target = "any.any.middle.suffix";
50+
List<String> res = names.stream()
51+
.filter(name -> matches(target, name))
52+
.sorted(KeyMatcher::compare)
53+
.collect(Collectors.toList());
54+
System.out.println(res);
55+
}
56+
57+
private static int compare(String firstExpression, String secondExpression) {
2958
String[] firstExpressionArr = getSeparated(firstExpression);
3059
String[] secondExpressionArr = getSeparated(secondExpression);
31-
for (int i = 0; i < firstExpressionArr.length && i < secondExpressionArr.length; i++) {
32-
if (firstExpressionArr[i].equals(secondExpressionArr[i])) {
33-
continue;
34-
}
35-
if (firstExpressionArr[i].equals(WILDCARD_CHAR)) {
36-
return 1;
37-
}
60+
return compare(secondExpressionArr.length - firstExpressionArr.length, firstExpressionArr, secondExpressionArr, 0);
61+
}
62+
63+
private static int compare(int current, String[] first, String[] second, int idx){
64+
if(idx >= first.length || idx >= second.length){
65+
return current;
66+
}
67+
if (first[idx].equals(second[idx])) {
68+
return compare(current, first, second, idx + 1);
69+
}
70+
if (!first[idx].equals(SINGLE_WORD_WILDCARD) && !first[idx].equals(MULTIPLE_WORD_WILDCARD)) {
3871
return -1;
3972
}
40-
return secondExpressionArr.length - firstExpressionArr.length;
73+
if (!second[idx].equals(SINGLE_WORD_WILDCARD) && !second[idx].equals(MULTIPLE_WORD_WILDCARD)) {
74+
return 1;
75+
}
76+
if (first[idx].equals(MULTIPLE_WORD_WILDCARD) && second[idx].equals(SINGLE_WORD_WILDCARD)) {
77+
return compare(1, first, second, idx + 1);
78+
}
79+
if (first[idx].equals(SINGLE_WORD_WILDCARD) && second[idx].equals(MULTIPLE_WORD_WILDCARD)) {
80+
return compare(-1, first, second, idx + 1);
81+
}
82+
return second.length - first.length;
83+
}
84+
85+
private static boolean matches(String routingKey, String pattern) {
86+
if (!pattern.contains(SINGLE_WORD_WILDCARD) && !pattern.contains(MULTIPLE_WORD_WILDCARD)) {
87+
return false;
88+
}
89+
// Convert RabbitMQ wildcard pattern to regex pattern
90+
String regexPattern = pattern.replace(".", "\\.")
91+
.replace("*", "[^.]+")
92+
.replace("#", ".*");
93+
94+
// Compile regex pattern
95+
Pattern p = Pattern.compile("^" + regexPattern + "$");
96+
97+
// Match routing key against regex pattern
98+
java.util.regex.Matcher m = p.matcher(routingKey);
99+
100+
return m.matches();
41101
}
42102

43-
private String[] getSeparated(String expression) {
103+
private static String[] getSeparated(String expression) {
44104
return expression.split(SEPARATOR_REGEX);
45105
}
46106
}

async/async-commons/src/test/java/org/reactivecommons/async/commons/utils/matcher/KeyMatcherTest.java

+27-10
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ public void init() {
1919
keyMatcher = new KeyMatcher();
2020
listeners = new HashSet<>();
2121
listeners.add("A.*");
22+
listeners.add("A.#");
2223
listeners.add("A.B");
2324
listeners.add("A.B.*");
25+
listeners.add("A.B.#");
2426
listeners.add("A.B.C");
2527
listeners.add("A.B.*.D");
2628
listeners.add("A.B.C.D");
@@ -49,6 +51,13 @@ void matchNonExistentSecondLevel() {
4951
assertEquals("A.B.*", match);
5052
}
5153

54+
@Test
55+
void matchExistentAnotherThirdLevel() {
56+
String nonExistentTarget = "A.B.X.Y";
57+
final String match = keyMatcher.match(listeners, nonExistentTarget);
58+
assertEquals("A.B.#", match);
59+
}
60+
5261
@Test
5362
void matchExistentSecondLevel() {
5463
String existentTarget = "A.B.C";
@@ -74,14 +83,14 @@ void matchExistentThirdLevel() {
7483
void matchDefaultForNonExistent() {
7584
String nonExistentTarget = "A.W.X.Y.Z";
7685
final String match = keyMatcher.match(listeners, nonExistentTarget);
77-
assertEquals("A.*", match);
86+
assertEquals("A.#", match);
7887
}
7988

8089
@Test
8190
void matchDefaultForNonExistentSecondLevel() {
8291
String nonExistentTarget = "A.B.X.Y.Z";
8392
final String match = keyMatcher.match(listeners, nonExistentTarget);
84-
assertEquals("A.B.*", match);
93+
assertEquals("A.B.#", match);
8594
}
8695

8796
@Test
@@ -109,12 +118,20 @@ void shouldNotMatchWhenNoWildcardSameLength() {
109118
void shouldApplyPriority() {
110119
listeners = new HashSet<>();
111120
listeners.add("*.*.*");
121+
listeners.add("*.#.*");
112122
listeners.add("prefix.*.*");
113-
listeners.add("*.middle.*");
123+
listeners.add("prefix.*.#");
114124
listeners.add("*.*.suffix");
125+
listeners.add("#.*.suffix");
115126
listeners.add("*.middle.suffix");
127+
listeners.add("#.middle.suffix");
128+
listeners.add("*.middle.*");
129+
listeners.add("*.middle.#");
130+
listeners.add("#.middle.#");
116131
listeners.add("prefix.*.suffix");
132+
listeners.add("prefix.#.suffix");
117133
listeners.add("prefix.middle.*");
134+
listeners.add("prefix.middle.#");
118135
listeners.add("prefix.middle.suffix");
119136
listeners.add("prefix.other.other");
120137
listeners.add("other.middle.other");
@@ -128,18 +145,18 @@ void shouldApplyPriority() {
128145
assertEquals("prefix.other.other", keyMatcher.match(listeners, "prefix.other.other"));
129146
assertEquals("prefix.middle.suffix", keyMatcher.match(listeners, "prefix.middle.suffix"));
130147
assertEquals("prefix.middle.*", keyMatcher.match(listeners, "prefix.middle.any"));
131-
assertEquals("prefix.middle.*", keyMatcher.match(listeners, "prefix.middle.any.any"));
148+
assertEquals("prefix.middle.#", keyMatcher.match(listeners, "prefix.middle.any.any"));
132149
assertEquals("prefix.*.suffix", keyMatcher.match(listeners, "prefix.any.suffix"));
133-
assertEquals("prefix.*.suffix", keyMatcher.match(listeners, "prefix.any.any.suffix"));
150+
assertEquals("prefix.#.suffix", keyMatcher.match(listeners, "prefix.any.any.suffix"));
134151
assertEquals("*.middle.suffix", keyMatcher.match(listeners, "any.middle.suffix"));
135-
assertEquals("*.middle.suffix", keyMatcher.match(listeners, "any.any.middle.suffix"));
152+
assertEquals("#.middle.suffix", keyMatcher.match(listeners, "any.any.middle.suffix"));
136153
assertEquals("*.*.suffix", keyMatcher.match(listeners, "any.any.suffix"));
137-
assertEquals("*.*.suffix", keyMatcher.match(listeners, "any.any.any.suffix"));
154+
assertEquals("#.*.suffix", keyMatcher.match(listeners, "any.any.any.suffix"));
138155
assertEquals("*.middle.*", keyMatcher.match(listeners, "any.middle.any"));
139-
assertEquals("*.middle.*", keyMatcher.match(listeners, "any.any.middle.any.any"));
156+
assertEquals("#.middle.#", keyMatcher.match(listeners, "any.any.middle.any.any"));
140157
assertEquals("prefix.*.*", keyMatcher.match(listeners, "prefix.any.any"));
141-
assertEquals("prefix.*.*", keyMatcher.match(listeners, "prefix.any.any.any.any"));
158+
assertEquals("prefix.*.#", keyMatcher.match(listeners, "prefix.any.any.any.any"));
142159
assertEquals("*.*.*", keyMatcher.match(listeners, "any.any.any"));
143-
assertEquals("*.*.*", keyMatcher.match(listeners, "any.any.any.any.any"));
160+
assertEquals("*.#.*", keyMatcher.match(listeners, "any.any.any.any.any"));
144161
}
145162
}

0 commit comments

Comments
 (0)