Skip to content

Commit d86588b

Browse files
committed
poc uaa throttling
1 parent 0960613 commit d86588b

File tree

5 files changed

+287
-8
lines changed

5 files changed

+287
-8
lines changed

cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/util/RequestLogger.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class RequestLogger {
3434
private long requestSentTime;
3535

3636
public void request(HttpClientRequest request) {
37-
request(String.format("%-6s {}", request.method()), request.uri());
37+
request(String.format("%-6s {}", request.method()), request.resourceUrl());
3838
}
3939

4040
public void response(HttpClientResponse response) {

integration-test/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@
7070
<version>${project.version}</version>
7171
<scope>test</scope>
7272
</dependency>
73+
<dependency>
74+
<groupId>io.github.resilience4j</groupId>
75+
<artifactId>resilience4j-ratelimiter</artifactId>
76+
<version>1.7.0</version>
77+
</dependency>
78+
<dependency>
79+
<groupId>io.github.resilience4j</groupId>
80+
<artifactId>resilience4j-reactor</artifactId>
81+
<version>1.7.0</version>
82+
</dependency>
7383
<dependency>
7484
<groupId>org.cloudfoundry</groupId>
7585
<artifactId>cloudfoundry-util</artifactId>

integration-test/src/test/java/org/cloudfoundry/IntegrationTestConfiguration.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,18 +192,18 @@ NetworkingClient adminNetworkingClient(
192192

193193
@Bean
194194
@Qualifier("admin")
195-
ReactorUaaClient adminUaaClient(
195+
UaaClient adminUaaClient(
196196
ConnectionContext connectionContext,
197197
@Value("${test.admin.clientId}") String clientId,
198198
@Value("${test.admin.clientSecret}") String clientSecret) {
199-
return ReactorUaaClient.builder()
199+
return new ThrottlingUaaClient(ReactorUaaClient.builder()
200200
.connectionContext(connectionContext)
201201
.tokenProvider(
202202
ClientCredentialsGrantTokenProvider.builder()
203203
.clientId(clientId)
204204
.clientSecret(clientSecret)
205205
.build())
206-
.build();
206+
.build());
207207
}
208208

209209
@Bean(initMethod = "block")
@@ -643,11 +643,11 @@ PasswordGrantTokenProvider tokenProvider(
643643
}
644644

645645
@Bean
646-
ReactorUaaClient uaaClient(ConnectionContext connectionContext, TokenProvider tokenProvider) {
647-
return ReactorUaaClient.builder()
646+
UaaClient uaaClient(ConnectionContext connectionContext, TokenProvider tokenProvider) {
647+
return new ThrottlingUaaClient(ReactorUaaClient.builder()
648648
.connectionContext(connectionContext)
649649
.tokenProvider(tokenProvider)
650-
.build();
650+
.build());
651651
}
652652

653653
@Bean(initMethod = "block")
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
package org.cloudfoundry;
2+
3+
import java.time.Duration;
4+
5+
import io.github.resilience4j.ratelimiter.RateLimiter;
6+
import io.github.resilience4j.ratelimiter.RateLimiterConfig;
7+
import io.github.resilience4j.reactor.ratelimiter.operator.RateLimiterOperator;
8+
import org.cloudfoundry.uaa.UaaClient;
9+
import org.cloudfoundry.uaa.authorizations.Authorizations;
10+
import org.cloudfoundry.uaa.clients.Clients;
11+
import org.cloudfoundry.uaa.groups.AddMemberRequest;
12+
import org.cloudfoundry.uaa.groups.AddMemberResponse;
13+
import org.cloudfoundry.uaa.groups.CheckMembershipRequest;
14+
import org.cloudfoundry.uaa.groups.CheckMembershipResponse;
15+
import org.cloudfoundry.uaa.groups.CreateGroupRequest;
16+
import org.cloudfoundry.uaa.groups.CreateGroupResponse;
17+
import org.cloudfoundry.uaa.groups.DeleteGroupRequest;
18+
import org.cloudfoundry.uaa.groups.DeleteGroupResponse;
19+
import org.cloudfoundry.uaa.groups.GetGroupRequest;
20+
import org.cloudfoundry.uaa.groups.GetGroupResponse;
21+
import org.cloudfoundry.uaa.groups.Groups;
22+
import org.cloudfoundry.uaa.groups.ListExternalGroupMappingsRequest;
23+
import org.cloudfoundry.uaa.groups.ListExternalGroupMappingsResponse;
24+
import org.cloudfoundry.uaa.groups.ListGroupsRequest;
25+
import org.cloudfoundry.uaa.groups.ListGroupsResponse;
26+
import org.cloudfoundry.uaa.groups.ListMembersRequest;
27+
import org.cloudfoundry.uaa.groups.ListMembersResponse;
28+
import org.cloudfoundry.uaa.groups.MapExternalGroupRequest;
29+
import org.cloudfoundry.uaa.groups.MapExternalGroupResponse;
30+
import org.cloudfoundry.uaa.groups.RemoveMemberRequest;
31+
import org.cloudfoundry.uaa.groups.RemoveMemberResponse;
32+
import org.cloudfoundry.uaa.groups.UnmapExternalGroupByGroupDisplayNameRequest;
33+
import org.cloudfoundry.uaa.groups.UnmapExternalGroupByGroupDisplayNameResponse;
34+
import org.cloudfoundry.uaa.groups.UnmapExternalGroupByGroupIdRequest;
35+
import org.cloudfoundry.uaa.groups.UnmapExternalGroupByGroupIdResponse;
36+
import org.cloudfoundry.uaa.groups.UpdateGroupRequest;
37+
import org.cloudfoundry.uaa.groups.UpdateGroupResponse;
38+
import org.cloudfoundry.uaa.identityproviders.IdentityProviders;
39+
import org.cloudfoundry.uaa.identityzones.IdentityZones;
40+
import org.cloudfoundry.uaa.serverinformation.ServerInformation;
41+
import org.cloudfoundry.uaa.tokens.Tokens;
42+
import org.cloudfoundry.uaa.users.ChangeUserPasswordRequest;
43+
import org.cloudfoundry.uaa.users.ChangeUserPasswordResponse;
44+
import org.cloudfoundry.uaa.users.CreateUserRequest;
45+
import org.cloudfoundry.uaa.users.CreateUserResponse;
46+
import org.cloudfoundry.uaa.users.DeleteUserRequest;
47+
import org.cloudfoundry.uaa.users.DeleteUserResponse;
48+
import org.cloudfoundry.uaa.users.ExpirePasswordRequest;
49+
import org.cloudfoundry.uaa.users.ExpirePasswordResponse;
50+
import org.cloudfoundry.uaa.users.GetUserVerificationLinkRequest;
51+
import org.cloudfoundry.uaa.users.GetUserVerificationLinkResponse;
52+
import org.cloudfoundry.uaa.users.InviteUsersRequest;
53+
import org.cloudfoundry.uaa.users.InviteUsersResponse;
54+
import org.cloudfoundry.uaa.users.ListUsersRequest;
55+
import org.cloudfoundry.uaa.users.ListUsersResponse;
56+
import org.cloudfoundry.uaa.users.LookupUserIdsRequest;
57+
import org.cloudfoundry.uaa.users.LookupUserIdsResponse;
58+
import org.cloudfoundry.uaa.users.UpdateUserRequest;
59+
import org.cloudfoundry.uaa.users.UpdateUserResponse;
60+
import org.cloudfoundry.uaa.users.UserInfoRequest;
61+
import org.cloudfoundry.uaa.users.UserInfoResponse;
62+
import org.cloudfoundry.uaa.users.Users;
63+
import org.cloudfoundry.uaa.users.VerifyUserRequest;
64+
import org.cloudfoundry.uaa.users.VerifyUserResponse;
65+
import reactor.core.publisher.Mono;
66+
67+
public class ThrottlingUaaClient implements UaaClient {
68+
69+
private final UaaClient delegate;
70+
71+
private final RateLimiter rateLimiter;
72+
private final ThrottledUsers users;
73+
private Groups groups;
74+
75+
public ThrottlingUaaClient(UaaClient delegate) {
76+
this.delegate = delegate;
77+
RateLimiterConfig config = RateLimiterConfig.custom()
78+
.limitForPeriod(5)
79+
.limitRefreshPeriod(Duration.ofSeconds(1))
80+
.build();
81+
this.rateLimiter = RateLimiter.of("uaa", config);
82+
this.users = new ThrottledUsers();
83+
this.groups = new ThrottledGroups();
84+
}
85+
86+
@Override
87+
public Authorizations authorizations() {
88+
return this.delegate.authorizations();
89+
}
90+
91+
@Override
92+
public Clients clients() {
93+
return this.delegate.clients();
94+
}
95+
96+
@Override
97+
public Mono<String> getUsername() {
98+
return this.delegate.getUsername();
99+
}
100+
101+
102+
@Override
103+
public IdentityProviders identityProviders() {
104+
return this.delegate.identityProviders();
105+
}
106+
107+
@Override
108+
public IdentityZones identityZones() {
109+
return this.delegate.identityZones();
110+
}
111+
112+
@Override
113+
public ServerInformation serverInformation() {
114+
return this.delegate.serverInformation();
115+
}
116+
117+
@Override
118+
public Tokens tokens() {
119+
return this.delegate.tokens();
120+
}
121+
122+
@Override
123+
public Users users() {
124+
return users;
125+
}
126+
127+
@Override
128+
public Groups groups() {
129+
return groups;
130+
}
131+
132+
public class ThrottledUsers implements Users {
133+
134+
private final Users usersDelegate;
135+
136+
public ThrottledUsers() {
137+
this.usersDelegate = delegate.users();
138+
}
139+
140+
@Override
141+
public Mono<ChangeUserPasswordResponse> changePassword(ChangeUserPasswordRequest request) {
142+
return this.usersDelegate.changePassword(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
143+
}
144+
145+
@Override
146+
public Mono<CreateUserResponse> create(CreateUserRequest request) {
147+
return this.usersDelegate.create(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
148+
}
149+
150+
@Override
151+
public Mono<DeleteUserResponse> delete(DeleteUserRequest request) {
152+
return this.usersDelegate.delete(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
153+
}
154+
155+
@Override
156+
public Mono<ExpirePasswordResponse> expirePassword(ExpirePasswordRequest request) {
157+
return this.usersDelegate.expirePassword(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
158+
}
159+
160+
@Override
161+
public Mono<GetUserVerificationLinkResponse> getVerificationLink(GetUserVerificationLinkRequest request) {
162+
return this.usersDelegate.getVerificationLink(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
163+
}
164+
165+
@Override
166+
public Mono<InviteUsersResponse> invite(InviteUsersRequest request) {
167+
return this.usersDelegate.invite(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
168+
}
169+
170+
@Override
171+
public Mono<ListUsersResponse> list(ListUsersRequest request) {
172+
return this.usersDelegate.list(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
173+
}
174+
175+
@Override
176+
public Mono<LookupUserIdsResponse> lookup(LookupUserIdsRequest request) {
177+
return this.usersDelegate.lookup(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
178+
}
179+
180+
@Override
181+
public Mono<UpdateUserResponse> update(UpdateUserRequest request) {
182+
return this.usersDelegate.update(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
183+
}
184+
185+
@Override
186+
public Mono<UserInfoResponse> userInfo(UserInfoRequest request) {
187+
return this.usersDelegate.userInfo(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
188+
}
189+
190+
@Override
191+
public Mono<VerifyUserResponse> verify(VerifyUserRequest request) {
192+
return this.usersDelegate.verify(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
193+
}
194+
}
195+
196+
public class ThrottledGroups implements Groups {
197+
198+
public final Groups groupsDelegate;
199+
200+
public ThrottledGroups() {
201+
this.groupsDelegate = delegate.groups();
202+
}
203+
204+
@Override
205+
public Mono<AddMemberResponse> addMember(AddMemberRequest request) {
206+
return this.groupsDelegate.addMember(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
207+
}
208+
209+
@Override
210+
public Mono<CheckMembershipResponse> checkMembership(CheckMembershipRequest request) {
211+
return this.groupsDelegate.checkMembership(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
212+
}
213+
214+
@Override
215+
public Mono<CreateGroupResponse> create(CreateGroupRequest request) {
216+
return this.groupsDelegate.create(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
217+
}
218+
219+
@Override
220+
public Mono<DeleteGroupResponse> delete(DeleteGroupRequest request) {
221+
return this.groupsDelegate.delete(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
222+
}
223+
224+
@Override
225+
public Mono<GetGroupResponse> get(GetGroupRequest request) {
226+
return this.groupsDelegate.get(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
227+
}
228+
229+
@Override
230+
public Mono<ListGroupsResponse> list(ListGroupsRequest request) {
231+
return this.groupsDelegate.list(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
232+
}
233+
234+
@Override
235+
public Mono<ListExternalGroupMappingsResponse> listExternalGroupMappings(ListExternalGroupMappingsRequest request) {
236+
return this.groupsDelegate.listExternalGroupMappings(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
237+
}
238+
239+
@Override
240+
public Mono<ListMembersResponse> listMembers(ListMembersRequest request) {
241+
return this.groupsDelegate.listMembers(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
242+
}
243+
244+
@Override
245+
public Mono<MapExternalGroupResponse> mapExternalGroup(MapExternalGroupRequest request) {
246+
return this.groupsDelegate.mapExternalGroup(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
247+
}
248+
249+
@Override
250+
public Mono<RemoveMemberResponse> removeMember(RemoveMemberRequest request) {
251+
return this.groupsDelegate.removeMember(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
252+
}
253+
254+
@Override
255+
public Mono<UnmapExternalGroupByGroupDisplayNameResponse> unmapExternalGroupByGroupDisplayName(UnmapExternalGroupByGroupDisplayNameRequest request) {
256+
return this.groupsDelegate.unmapExternalGroupByGroupDisplayName(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
257+
}
258+
259+
@Override
260+
public Mono<UnmapExternalGroupByGroupIdResponse> unmapExternalGroupByGroupId(UnmapExternalGroupByGroupIdRequest request) {
261+
return this.groupsDelegate.unmapExternalGroupByGroupId(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
262+
}
263+
264+
@Override
265+
public Mono<UpdateGroupResponse> update(UpdateGroupRequest request) {
266+
return this.groupsDelegate.update(request).transformDeferred(RateLimiterOperator.of(rateLimiter));
267+
}
268+
}
269+
}

integration-test/src/test/resources/logback-test.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
<logger name="cloudfoundry-client.compatibility" level="${CLIENT_LOGGING_LEVEL:-INFO}"/>
2727
<logger name="cloudfoundry-client.delay" level="${CLIENT_LOGGING_LEVEL:-INFO}"/>
2828
<logger name="cloudfoundry-client.operations" level="${CLIENT_LOGGING_LEVEL:-INFO}"/>
29-
<logger name="cloudfoundry-client.request" level="${CLIENT_LOGGING_LEVEL:-INFO}"/>
29+
<logger name="cloudfoundry-client.request" level="DEBUG"/>
3030
<logger name="cloudfoundry-client.resource-matching" level="${CLIENT_LOGGING_LEVEL:-INFO}"/>
3131
<logger name="cloudfoundry-client.response" level="${CLIENT_LOGGING_LEVEL:-INFO}"/>
3232
<logger name="cloudfoundry-client.test" level="${TEST_LOGGING_LEVEL:-INFO}"/>

0 commit comments

Comments
 (0)