1
1
package com .iluwatar .rate .limiting .pattern ;
2
2
3
- import java .util .Random ;
3
+ import org .slf4j .Logger ;
4
+ import org .slf4j .LoggerFactory ;
4
5
import java .util .concurrent .*;
5
6
import java .util .concurrent .atomic .AtomicBoolean ;
6
7
import java .util .concurrent .atomic .AtomicInteger ;
43
44
* variable load.
44
45
*/
45
46
public final class App {
47
+ private static final Logger LOGGER = LoggerFactory .getLogger (App .class );
48
+
46
49
private static final int RUN_DURATION_SECONDS = 10 ;
47
50
private static final int SHUTDOWN_TIMEOUT_SECONDS = 5 ;
48
51
49
- private static final AtomicInteger successfulRequests = new AtomicInteger ();
50
- private static final AtomicInteger throttledRequests = new AtomicInteger ();
51
- private static final AtomicInteger failedRequests = new AtomicInteger ();
52
- private static final AtomicBoolean running = new AtomicBoolean (true );
52
+ static final AtomicInteger successfulRequests = new AtomicInteger ();
53
+ static final AtomicInteger throttledRequests = new AtomicInteger ();
54
+ static final AtomicInteger failedRequests = new AtomicInteger ();
55
+ static final AtomicBoolean running = new AtomicBoolean (true );
56
+ private static final String DIVIDER_LINE = "====================================" ;
53
57
54
58
public static void main (String [] args ) {
55
- System . out . println ( " \n Starting Rate Limiter Demo" );
56
- System . out . println ( "====================================" );
59
+ LOGGER . info ( "Starting Rate Limiter Demo" );
60
+ LOGGER . info ( DIVIDER_LINE );
57
61
58
62
ExecutorService executor = Executors .newFixedThreadPool (3 );
59
63
ScheduledExecutorService statsPrinter = Executors .newSingleThreadScheduledExecutor ();
60
64
61
65
try {
62
- // Explicit limiter setup for demonstration clarity
63
- TokenBucketRateLimiter tb = new TokenBucketRateLimiter (2 , 1 ); // capacity 2, refill 1/sec
64
- FixedWindowRateLimiter fw = new FixedWindowRateLimiter (3 , 1 ); // max 3 req/sec
65
- AdaptiveRateLimiter ar = new AdaptiveRateLimiter (2 , 6 ); // adaptive from 2 to 6 req/sec
66
+ TokenBucketRateLimiter tb = new TokenBucketRateLimiter (2 , 1 );
67
+ FixedWindowRateLimiter fw = new FixedWindowRateLimiter (3 , 1 );
68
+ AdaptiveRateLimiter ar = new AdaptiveRateLimiter (2 , 6 );
66
69
67
- // Print statistics every 2 seconds
68
70
statsPrinter .scheduleAtFixedRate (App ::printStats , 2 , 2 , TimeUnit .SECONDS );
69
71
70
- // Launch 3 simulated clients
71
72
for (int i = 1 ; i <= 3 ; i ++) {
72
73
executor .submit (createClientTask (i , tb , fw , ar ));
73
74
}
74
75
75
- // Run simulation for N seconds
76
76
Thread .sleep (RUN_DURATION_SECONDS * 1000L );
77
- System .out .println ("\n Shutting down the demo..." );
78
-
77
+ LOGGER .info ("Shutting down the demo..." );
78
+ } catch (InterruptedException e ) {
79
+ Thread .currentThread ().interrupt ();
80
+ } finally {
79
81
running .set (false );
80
- executor .shutdown ();
81
- statsPrinter .shutdown ();
82
+ shutdownExecutor (executor , "mainExecutor" );
83
+ shutdownExecutor (statsPrinter , "statsPrinter" );
84
+ printFinalStats ();
85
+ LOGGER .info ("Demo completed." );
86
+ }
87
+ }
82
88
83
- if (!executor .awaitTermination (SHUTDOWN_TIMEOUT_SECONDS , TimeUnit .SECONDS )) {
84
- executor .shutdownNow ();
85
- }
86
- if (!statsPrinter .awaitTermination (SHUTDOWN_TIMEOUT_SECONDS , TimeUnit .SECONDS )) {
87
- statsPrinter .shutdownNow ();
89
+ private static void shutdownExecutor (ExecutorService service , String name ) {
90
+ service .shutdown ();
91
+ try {
92
+ if (!service .awaitTermination (SHUTDOWN_TIMEOUT_SECONDS , TimeUnit .SECONDS )) {
93
+ service .shutdownNow ();
94
+ LOGGER .warn ("Forced shutdown of {}" , name );
88
95
}
89
-
90
96
} catch (InterruptedException e ) {
97
+ service .shutdownNow ();
91
98
Thread .currentThread ().interrupt ();
92
- } finally {
93
- printFinalStats ();
94
- System .out .println ("Demo completed." );
95
99
}
96
100
}
97
101
98
- private static Runnable createClientTask (
99
- int clientId , RateLimiter s3Limiter , RateLimiter dynamoDbLimiter , RateLimiter lambdaLimiter ) {
102
+ static Runnable createClientTask (int clientId , RateLimiter s3Limiter , RateLimiter dynamoDbLimiter , RateLimiter lambdaLimiter ) {
100
103
return () -> {
101
104
String [] services = {"s3" , "dynamodb" , "lambda" };
102
- String [] operations = {
103
- "GetObject" , "PutObject" , "Query" , "Scan" , "PutItem" , "Invoke" , "ListFunctions"
104
- };
105
- Random random = new Random ();
105
+ String [] operations = {"GetObject" , "PutObject" , "Query" , "Scan" , "PutItem" , "Invoke" , "ListFunctions" };
106
+ ThreadLocalRandom random = ThreadLocalRandom .current ();
106
107
107
108
while (running .get () && !Thread .currentThread ().isInterrupted ()) {
108
109
try {
@@ -113,52 +114,55 @@ private static Runnable createClientTask(
113
114
case "s3" -> makeRequest (clientId , s3Limiter , service , operation );
114
115
case "dynamodb" -> makeRequest (clientId , dynamoDbLimiter , service , operation );
115
116
case "lambda" -> makeRequest (clientId , lambdaLimiter , service , operation );
117
+ default -> LOGGER .warn ("Unknown service: {}" , service );
116
118
}
117
119
118
- Thread .sleep (30 + random .nextInt (50 ));
120
+ Thread .sleep (30L + random .nextInt (50 ));
119
121
} catch (InterruptedException e ) {
120
122
Thread .currentThread ().interrupt ();
121
123
}
122
124
}
123
125
};
124
126
}
125
127
126
- private static void makeRequest (
127
- int clientId , RateLimiter limiter , String service , String operation ) {
128
+ static void makeRequest (int clientId , RateLimiter limiter , String service , String operation ) {
128
129
try {
129
130
limiter .check (service , operation );
130
131
successfulRequests .incrementAndGet ();
131
- System . out . printf ("Client %d: %s.%s - ALLOWED%n " , clientId , service , operation );
132
+ LOGGER . info ("Client {}: {}.{} - ALLOWED" , clientId , service , operation );
132
133
} catch (ThrottlingException e ) {
133
134
throttledRequests .incrementAndGet ();
134
- System .out .printf (
135
- "Client %d: %s.%s - THROTTLED (Retry in %dms)%n" ,
136
- clientId , service , operation , e .getRetryAfterMillis ());
135
+ LOGGER .warn ("Client {}: {}.{} - THROTTLED (Retry in {}ms)" , clientId , service , operation , e .getRetryAfterMillis ());
137
136
} catch (ServiceUnavailableException e ) {
138
137
failedRequests .incrementAndGet ();
139
- System . out . printf ("Client %d: %s.%s - SERVICE UNAVAILABLE%n " , clientId , service , operation );
138
+ LOGGER . warn ("Client {}: {}.{} - SERVICE UNAVAILABLE" , clientId , service , operation );
140
139
} catch (Exception e ) {
141
140
failedRequests .incrementAndGet ();
142
- System .out .printf (
143
- "Client %d: %s.%s - ERROR: %s%n" , clientId , service , operation , e .getMessage ());
141
+ LOGGER .error ("Client {}: {}.{} - ERROR: {}" , clientId , service , operation , e .getMessage ());
144
142
}
145
143
}
146
144
147
- private static void printStats () {
145
+ static void printStats () {
148
146
if (!running .get ()) return ;
149
- System .out .println ("\n === Current Statistics ===" );
150
- System .out .printf ("Successful Requests: %d%n" , successfulRequests .get ());
151
- System .out .printf ("Throttled Requests : %d%n" , throttledRequests .get ());
152
- System .out .printf ("Failed Requests : %d%n" , failedRequests .get ());
153
- System .out .println ("==========================\n " );
147
+ LOGGER .info ("=== Current Statistics ===" );
148
+ LOGGER .info ("Successful Requests: {}" , successfulRequests .get ());
149
+ LOGGER .info ("Throttled Requests : {}" , throttledRequests .get ());
150
+ LOGGER .info ("Failed Requests : {}" , failedRequests .get ());
151
+ LOGGER .info (DIVIDER_LINE );
152
+ }
153
+
154
+ static void printFinalStats () {
155
+ LOGGER .info ("Final Statistics" );
156
+ LOGGER .info (DIVIDER_LINE );
157
+ LOGGER .info ("Successful Requests: {}" , successfulRequests .get ());
158
+ LOGGER .info ("Throttled Requests : {}" , throttledRequests .get ());
159
+ LOGGER .info ("Failed Requests : {}" , failedRequests .get ());
160
+ LOGGER .info (DIVIDER_LINE );
154
161
}
155
162
156
- private static void printFinalStats () {
157
- System .out .println ("\n Final Statistics" );
158
- System .out .println ("==========================" );
159
- System .out .printf ("Successful Requests: %d%n" , successfulRequests .get ());
160
- System .out .printf ("Throttled Requests : %d%n" , throttledRequests .get ());
161
- System .out .printf ("Failed Requests : %d%n" , failedRequests .get ());
162
- System .out .println ("==========================" );
163
+ static void resetCountersForTesting () {
164
+ successfulRequests .set (0 );
165
+ throttledRequests .set (0 );
166
+ failedRequests .set (0 );
163
167
}
164
168
}
0 commit comments