Skip to content

Commit 50d7dbe

Browse files
author
Deepanshu Rastogi
committed
Seperated timer class and created Callscount class
1 parent 5f9100c commit 50d7dbe

File tree

12 files changed

+266
-89
lines changed

12 files changed

+266
-89
lines changed

throttling/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ tags:
1010
---
1111

1212
## Intent
13-
Ensure that a given tenant is not able to access resources more than the assigned limit.
13+
Ensure that a given client is not able to access service resources more than the assigned limit.
1414
![alt text](./etc/throttling-patern.png "Throttling pattern")
1515

1616
## Applicability
1717
The Throttling pattern should be used:
1818

1919
* when a service access needs to be restricted to not have high impacts on the performance of the service.
20-
* when multiple tenants are consuming the same resources and restriction has to be made according to the usage per tenant.
20+
* when multiple clients are consuming the same service resources and restriction has to be made according to the usage per client.

throttling/etc/throttling-patern.png

-65.9 KB
Binary file not shown.

throttling/etc/throttling-pattern.png

59 KB
Loading

throttling/src/main/java/com/iluwatar/tls/App.java renamed to throttling/src/main/java/com/iluwatar/throttling/App.java

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,17 @@
2121
* THE SOFTWARE.
2222
*/
2323

24-
package com.iluwatar.tls;
24+
package com.iluwatar.throttling;
2525

2626
import org.slf4j.Logger;
2727
import org.slf4j.LoggerFactory;
2828

29-
import java.nio.file.AccessDeniedException;
29+
import com.iluwatar.throttling.timer.Throttler;
30+
import com.iluwatar.throttling.timer.ThrottleTimerImpl;
31+
32+
import java.util.concurrent.ExecutorService;
33+
import java.util.concurrent.Executors;
34+
import java.util.concurrent.TimeUnit;
3035

3136
/**
3237
* Throttling pattern is a design pattern to throttle or limit the use of resources or even a complete service by
@@ -49,36 +54,36 @@ public class App {
4954
*/
5055
public static void main(String[] args) {
5156

52-
Tenant adidas = new Tenant("Adidas", 80);
53-
Tenant nike = new Tenant("Nike", 70);
54-
55-
B2BService adidasService = new B2BService(adidas);
56-
B2BService nikeService = new B2BService(nike);
57+
Tenant adidas = new Tenant("Adidas", 5);
58+
Tenant nike = new Tenant("Nike", 6);
5759

58-
Runnable adidasTask = () -> makeServiceCalls(adidasService);
59-
Runnable nikeTask = () -> makeServiceCalls(nikeService);
60-
61-
new Thread(adidasTask).start();
62-
new Thread(nikeTask).start();
60+
ExecutorService executorService = Executors.newFixedThreadPool(2);
61+
62+
executorService.execute(() -> makeServiceCalls(adidas));
63+
executorService.execute(() -> makeServiceCalls(nike));
64+
65+
executorService.shutdown();
66+
try {
67+
executorService.awaitTermination(10, TimeUnit.SECONDS);
68+
} catch (InterruptedException e) {
69+
LOGGER.error("Executor Service terminated: {}", e.getMessage());
70+
}
6371
}
6472

6573
/**
6674
* Make calls to the B2BService dummy API
6775
* @param service an instance of B2BService
6876
*/
69-
private static void makeServiceCalls(B2BService service) {
70-
for (int i = 0; i < 500; i++) {
77+
private static void makeServiceCalls(Tenant tenant) {
78+
Throttler timer = new ThrottleTimerImpl(10);
79+
B2BService service = new B2BService(timer);
80+
for (int i = 0; i < 20; i++) {
81+
service.dummyCustomerApi(tenant);
82+
// Sleep is introduced to keep the output in check and easy to view and analyze the results.
7183
try {
72-
service.dummyCustomerApi();
73-
// This block is introduced to keep the output in check and easy to view and analyze the results.
74-
try {
75-
Thread.sleep(10);
76-
} catch (InterruptedException e) {
77-
e.printStackTrace();
78-
}
79-
// It can be removed if required.
80-
} catch (AccessDeniedException e) {
81-
LOGGER.error("### {} ###", e.getMessage());
84+
Thread.sleep(1);
85+
} catch (InterruptedException e) {
86+
LOGGER.error("Thread interrupted: {}", e.getMessage());
8287
}
8388
}
8489
}

throttling/src/main/java/com/iluwatar/tls/B2BService.java renamed to throttling/src/main/java/com/iluwatar/throttling/B2BService.java

Lines changed: 13 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -20,67 +20,43 @@
2020
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
* THE SOFTWARE.
2222
*/
23-
package com.iluwatar.tls;
23+
package com.iluwatar.throttling;
2424

2525
import org.slf4j.Logger;
2626
import org.slf4j.LoggerFactory;
2727

28-
import java.nio.file.AccessDeniedException;
29-
import java.util.Timer;
30-
import java.util.TimerTask;
28+
import com.iluwatar.throttling.timer.Throttler;
29+
3130
import java.util.concurrent.ThreadLocalRandom;
3231

3332
/**
3433
* A service which accepts a tenant and throttles the resource based on the time given to the tenant.
3534
*/
3635
class B2BService {
3736

38-
private Tenant tenant;
39-
private int callsCounter;
40-
4137
private static final Logger LOGGER = LoggerFactory.getLogger(B2BService.class);
4238

43-
/**
44-
* A timer is initiated as soon as the Service is initiated. The timer runs every minute and resets the
45-
* counter.
46-
* @param tenant the Tenant which will consume the service.
47-
*/
48-
public B2BService(Tenant tenant) {
49-
this.tenant = tenant;
50-
Timer timer = new Timer(true);
51-
52-
timer.schedule(new TimerTask() {
53-
@Override
54-
public void run() {
55-
callsCounter = 0;
56-
}
57-
}, 0, 1000);
39+
public B2BService(Throttler timer) {
40+
timer.start();
5841
}
5942

6043
/**
6144
*
6245
* @return customer id which is randomly generated
63-
* @throws AccessDeniedException when the limit is reached
6446
*/
65-
public int dummyCustomerApi() throws AccessDeniedException {
66-
LOGGER.debug("Counter for {} : {} ", tenant.getName(), callsCounter);
67-
68-
if (callsCounter >= tenant.getAllowedCallsPerSecond()) {
69-
throw new AccessDeniedException("API access per second limit reached for: " + tenant.getName());
47+
public int dummyCustomerApi(Tenant tenant) {
48+
String tenantName = tenant.getName();
49+
int count = CallsCount.getCount(tenantName);
50+
LOGGER.debug("Counter for {} : {} ", tenant.getName(), count);
51+
if (count >= tenant.getAllowedCallsPerSecond()) {
52+
LOGGER.error("API access per second limit reached for: {}", tenantName);
53+
return -1;
7054
}
71-
callsCounter++;
55+
CallsCount.incrementCount(tenantName);
7256
return getRandomCustomerId();
7357
}
7458

7559
private int getRandomCustomerId() {
7660
return ThreadLocalRandom.current().nextInt(1, 10000);
7761
}
78-
79-
/**
80-
*
81-
* @return current count of the calls made.
82-
*/
83-
public int getCurrentCallsCount() {
84-
return callsCounter;
85-
}
8662
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* The MIT License
3+
* Copyright (c) 2014 Ilkka Seppälä
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
package com.iluwatar.throttling;
24+
25+
import java.util.Map;
26+
import java.util.Map.Entry;
27+
import java.util.concurrent.ConcurrentHashMap;
28+
29+
/**
30+
* A class to keep track of the counter of different Tenants
31+
* @author drastogi
32+
*
33+
*/
34+
public final class CallsCount {
35+
private static Map<String, Integer> tenantCallsCount = new ConcurrentHashMap<>();
36+
37+
/**
38+
* Add a new tenant to the map.
39+
* @param tenantName name of the tenant.
40+
*/
41+
public static void addTenant(String tenantName) {
42+
if (!tenantCallsCount.containsKey(tenantName)) {
43+
tenantCallsCount.put(tenantName, 0);
44+
}
45+
}
46+
47+
/**
48+
* Increment the count of the specified tenant.
49+
* @param tenantName name of the tenant.
50+
*/
51+
public static void incrementCount(String tenantName) {
52+
tenantCallsCount.put(tenantName, tenantCallsCount.get(tenantName) + 1);
53+
}
54+
55+
/**
56+
*
57+
* @param tenantName name of the tenant.
58+
* @return the count of the tenant.
59+
*/
60+
public static int getCount(String tenantName) {
61+
return tenantCallsCount.get(tenantName);
62+
}
63+
64+
/**
65+
* Resets the count of all the tenants in the map.
66+
*/
67+
public static void reset() {
68+
for (Entry<String, Integer> e : tenantCallsCount.entrySet()) {
69+
tenantCallsCount.put(e.getKey(), 0);
70+
}
71+
}
72+
}

throttling/src/main/java/com/iluwatar/tls/Tenant.java renamed to throttling/src/main/java/com/iluwatar/throttling/Tenant.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2121
* THE SOFTWARE.
2222
*/
23-
package com.iluwatar.tls;
23+
package com.iluwatar.throttling;
2424

2525
import java.security.InvalidParameterException;
2626

@@ -44,21 +44,14 @@ public Tenant(String name, int allowedCallsPerSecond) {
4444
}
4545
this.name = name;
4646
this.allowedCallsPerSecond = allowedCallsPerSecond;
47+
CallsCount.addTenant(name);
4748
}
4849

4950
public String getName() {
5051
return name;
5152
}
5253

53-
public void setName(String name) {
54-
this.name = name;
55-
}
56-
5754
public int getAllowedCallsPerSecond() {
5855
return allowedCallsPerSecond;
5956
}
60-
61-
public void setAllowedCallsPerSecond(int allowedCallsPerSecond) {
62-
this.allowedCallsPerSecond = allowedCallsPerSecond;
63-
}
6457
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* The MIT License
3+
* Copyright (c) 2014 Ilkka Seppälä
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
/**
24+
*
25+
*/
26+
package com.iluwatar.throttling.timer;
27+
28+
import java.util.Timer;
29+
import java.util.TimerTask;
30+
31+
import com.iluwatar.throttling.CallsCount;
32+
33+
/**
34+
* Implementation of throttler interface. This class resets the counter every second.
35+
* @author drastogi
36+
*
37+
*/
38+
public class ThrottleTimerImpl implements Throttler{
39+
40+
private int throttlePeriod;
41+
42+
public ThrottleTimerImpl(int throttlePeriod) {
43+
this.throttlePeriod = throttlePeriod;
44+
}
45+
46+
/**
47+
* A timer is initiated with this method. The timer runs every second and resets the
48+
* counter.
49+
*/
50+
public void start() {
51+
new Timer(true).schedule(new TimerTask() {
52+
@Override
53+
public void run() {
54+
CallsCount.reset();
55+
}
56+
}, 0, throttlePeriod);
57+
}
58+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* The MIT License
3+
* Copyright (c) 2014 Ilkka Seppälä
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
/**
24+
*
25+
*/
26+
package com.iluwatar.throttling.timer;
27+
28+
/**
29+
* An interface for defining the structure of different types of throttling ways.
30+
* @author drastogi
31+
*
32+
*/
33+
public interface Throttler {
34+
35+
void start();
36+
}

0 commit comments

Comments
 (0)