-
Notifications
You must be signed in to change notification settings - Fork 243
feat: async user request processor #253
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,16 +1,40 @@ | ||
| package mate.academy; | ||
|
|
||
| import java.util.Map; | ||
| import java.util.concurrent.CompletableFuture; | ||
| import java.util.concurrent.ConcurrentHashMap; | ||
| import java.util.concurrent.Executor; | ||
| import java.util.concurrent.TimeUnit; | ||
|
|
||
| public class AsyncRequestProcessor { | ||
| private final Executor executor; | ||
| private final Map<String, UserData> cache = new ConcurrentHashMap<>(); | ||
| private final Map<String, CompletableFuture<UserData>> inFlight = new ConcurrentHashMap<>(); | ||
|
|
||
| public AsyncRequestProcessor(Executor executor) { | ||
| this.executor = executor; | ||
| } | ||
|
|
||
| public CompletableFuture<UserData> processRequest(String userId) { | ||
| return null; | ||
| if (cache.containsKey(userId)) { | ||
| return CompletableFuture.completedFuture(cache.get(userId)); | ||
| } | ||
|
|
||
| return inFlight.computeIfAbsent(userId, id -> CompletableFuture.supplyAsync(() -> { | ||
| try { | ||
| TimeUnit.MILLISECONDS.sleep(500); | ||
| } catch (InterruptedException e) { | ||
| Thread.currentThread().interrupt(); | ||
| throw new RuntimeException("Task was interrupted for user " + id, e); | ||
| } | ||
| return new UserData(id, "Details for " + id); | ||
| }, executor) | ||
| .whenComplete((userData, ex) -> { | ||
| if (ex == null) { | ||
| cache.put(id, userData); | ||
| } | ||
| inFlight.remove(id); | ||
| }) | ||
| ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,24 +2,26 @@ | |
|
|
||
| import java.util.concurrent.CompletableFuture; | ||
| import java.util.concurrent.ExecutorService; | ||
| import java.util.concurrent.Executors; | ||
|
|
||
| public class Main { | ||
| public static void main(String[] args) { | ||
| // Feel free to play with AsyncRequestProcessor in this main method if you want | ||
| ExecutorService executor = null; // Provide implementation that fits your needs | ||
| ExecutorService executor = Executors.newFixedThreadPool(4); | ||
| AsyncRequestProcessor asyncRequestProcessor = new AsyncRequestProcessor(executor); | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The task description explicitly requires declaring the cache exactly as |
||
| // Simulating multiple concurrent requests | ||
| String[] userIds = {"user1", "user2", "user3", "user1"}; // Note: "user1" is repeated | ||
| String[] userIds = {"user1", "user2", "user3", "user1"}; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The input |
||
| CompletableFuture<?>[] futures = new CompletableFuture[userIds.length]; | ||
|
|
||
| for (int i = 0; i < userIds.length; i++) { | ||
| String userId = userIds[i]; | ||
| futures[i] = asyncRequestProcessor.processRequest(userId) | ||
| .thenAccept(userData -> System.out.println("Processed: " + userData)); | ||
| .thenAccept(userData -> System.out.println("Processed: " + userData)) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Printing the result inside There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Printing the results inside the asynchronous callback ( |
||
| .exceptionally(ex -> { | ||
| System.err.println("Error processing " + userId + ": " + ex.getMessage()); | ||
| return null; | ||
| }); | ||
| } | ||
|
|
||
| // Wait for all futures to complete | ||
| CompletableFuture.allOf(futures).join(); | ||
| executor.shutdown(); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,24 @@ | ||
| package mate.academy; | ||
|
|
||
| public record UserData(String userId, String details) { | ||
| public class UserData { | ||
| private final String userId; | ||
| private final String details; | ||
|
|
||
| public UserData(String userId, String details) { | ||
| this.userId = userId; | ||
| this.details = details; | ||
| } | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The task description explicitly requires the cache to be declared exactly as |
||
| public String userId() { | ||
| return userId; | ||
| } | ||
|
|
||
| public String details() { | ||
| return details; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Printing the results inside |
||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "UserData[userId=" + userId + ", details=" + details + "]"; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Printing the result directly in the asynchronous callback can lead to nondeterministic ordering of console output compared to the sample. If tests require exact ordering, consider collecting results and printing them in the original input order after all futures complete (or otherwise coordinate printing). Note: your caching logic already returns completed futures for cached entries, but concurrent completion timing can still reorder prints.