Skip to content

Task to check#236

Open
JacekKubiak80 wants to merge 3 commits into
mate-academy:mainfrom
JacekKubiak80:develop
Open

Task to check#236
JacekKubiak80 wants to merge 3 commits into
mate-academy:mainfrom
JacekKubiak80:develop

Conversation

@JacekKubiak80

Copy link
Copy Markdown

No description provided.

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

I am requesting changes because there are a few critical issues that will prevent the solution from matching the required behavior and expected output. First, AsyncRequestProcessor references UserData, but there is no confirmed UserData class with the required fields and toString() format; without this, the project may not compile or the printed lines will not match the expected UserData[userId=..., details=...] format (add userId, details fields and override toString() exactly as specified). Second, the details text is currently generated in Polish ("Szczegóły dla użytkownika " + userId), while the task requires English "Details for " + userId, and in Main the prefix "Przetworzono: " must be changed to "Processed: " to match the expected console output. Third, because you only put results into the cache after processing completes, two concurrent calls for the same userId can both start expensive work; you should instead cache an in-progress CompletableFuture<UserData> (e.g., via a Map<String, CompletableFuture<UserData>> and computeIfAbsent) so duplicates share the same future. Finally, printing directly inside thenAccept makes output ordering depend on completion timing; to guarantee the exact required order, collect futures (keeping their original indices) and print all results after CompletableFuture.allOf(...).join(). Once these are fixed, your asynchronous design and cache usage will align well with the task requirements—your current structure is solid, it just needs these adjustments to be fully correct.


✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨

Important

Fix the issues, commit the changes, and then re-request my review using the Re-request review button2 in the Reviewers tab.

Tip

If you have any comments about this review, please leave a message in the Add a comment section below and mention me with the @mateacademy-ai-mentor tag3.
I will read your message during my next review of your pull request. Please do not reply directly to my comments, as that feature is not supported yet.

Caution

Do not close the pull request until the review is complete. Closing it early can lead to unexpected behavior and disrupt the review process.

Footnotes

  1. Rate AI review example

  2. Re-request AI review example

  3. Add AI review comments example

public class AsyncRequestProcessor {

private final Executor executor;
private final Map<String, UserData> cache = new ConcurrentHashMap<>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file references UserData in the cache declaration. Ensure a UserData class exists with fields userId and details, and override toString() to return exactly UserData[userId=..., details=...] so output matches the task's expected console lines.

simulateDelay();

UserData userData =
new UserData(userId, "Szczegóły dla użytkownika " + userId);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The details string is created in Polish: "Szczegóły dla użytkownika " + userId. The task's expected output uses English Details for <userId>. Change this to "Details for " + userId so the produced UserData contains the expected text.

if (cachedData != null) {
return CompletableFuture.completedFuture(cachedData);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You check the cache before starting async work, but only call cache.put(...) after processing completes. This allows two concurrent requests for the same userId to both perform the expensive work. To meet the requirement that repeated requests be served from cache and reduce response time, consider caching the in-progress CompletableFuture<UserData> (e.g. a Map<String, CompletableFuture<UserData>> or computeIfAbsent) so subsequent requests reuse the same future.


// Simulating multiple concurrent requests
String[] userIds = {"user1", "user2", "user3", "user1"}; // Note: "user1" is repeated
String[] userIds = {"user1", "user2", "user3", "user1"};

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The input array matches the requirement ({"user1", "user2", "user3", "user1"}). If the tests expect the exact ordering from the spec, avoid printing inside thenAccept. Instead collect results together with their original index and print them in input order after CompletableFuture.allOf(...).join() so the console sequence matches the required output.

Comment thread src/main/java/mate/academy/Main.java Outdated
String userId = userIds[i];
futures[i] = asyncRequestProcessor.processRequest(userId)
.thenAccept(userData -> System.out.println("Processed: " + userData));
.thenAccept(userData ->

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're printing the result inside the completion callback which makes output ordering depend on completion timing. To guarantee the exact required ordering, gather results and print after all futures complete rather than printing directly inside thenAccept. This will ensure deterministic output order.

Comment thread src/main/java/mate/academy/Main.java Outdated
futures[i] = asyncRequestProcessor.processRequest(userId)
.thenAccept(userData -> System.out.println("Processed: " + userData));
.thenAccept(userData ->
System.out.println("Przetworzono: " + userData));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The printed prefix is Polish ("Przetworzono: "). Change it to "Processed: " so the console lines match the expected output format in the task description (e.g. Processed: UserData[userId=user1, details=Details for user1]).

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

I am requesting changes because a few core assignment requirements are not yet met, and they directly affect both functionality and grading. In AsyncRequestProcessor.java, the cache is currently Map<String, CompletableFuture<UserData>>, but the task explicitly requires Map<String, UserData> cache = new ConcurrentHashMap<>(); and that you first check this cache for a completed UserData and return CompletableFuture.completedFuture(cached) when present ([CHECKLIST ITEMS #10#13]). To fix this, keep the required Map<String, UserData> cache for finished results and add a separate Map<String, CompletableFuture<UserData>> inFlight using computeIfAbsent so concurrent calls for the same id share the same future; when the future completes, store the UserData into cache and remove the entry from inFlight. In Main.java, the console output prefix is currently Polish ("Przetworzono: "), but the expected exact text is "Processed: ", so the line that prints results must be updated to use that exact prefix ([CHECKLIST ITEMS #7, #17]). Additionally, printing only after CompletableFuture.allOf(...).join() means results appear in the input order, whereas the task expects faster/cached results to appear earlier; update the printing logic so each result is printed as its future completes (e.g., via thenAccept or similar). Once you adjust the cache design and the output text/ordering, your solution will align well with the requirements—your current use of CompletableFuture and UserData construction is otherwise solid and on the right track.


✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨

Important

Fix the issues, commit the changes, and then re-request my review using the Re-request review button2 in the Reviewers tab.

Tip

If you have any comments about this review, please leave a message in the Add a comment section below and mention me with the @mateacademy-ai-mentor tag3.
I will read your message during my next review of your pull request. Please do not reply directly to my comments, as that feature is not supported yet.

Caution

Do not close the pull request until the review is complete. Closing it early can lead to unexpected behavior and disrupt the review process.

Footnotes

  1. Rate AI review example

  2. Re-request AI review example

  3. Add AI review comments example

public class AsyncRequestProcessor {

private final Executor executor;
private final Map<String, CompletableFuture<UserData>> cache =

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache is declared as Map<String, CompletableFuture<UserData>>. The requirements explicitly require Map<String, UserData> cache = new ConcurrentHashMap<>(); (checklist items #10 and #11). Change the declaration to store UserData results as required. If you need to avoid duplicate work, keep a separate Map<String, CompletableFuture<UserData>> inFlight for in-progress operations instead of changing the required cache type.


public CompletableFuture<UserData> processRequest(String userId) {
return null;
return cache.computeIfAbsent(userId, id ->

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using computeIfAbsent on this cache stores in-progress CompletableFutures in the result cache. That prevents you from implementing the required behavior of checking the cache for a completed UserData and returning it immediately (checklist item #12). Instead: (a) check the Map<String, UserData> cache first and return CompletableFuture.completedFuture(cached) when present; (b) for new work, computeIfAbsent on a separate inFlight map of CompletableFuture<UserData> so concurrent callers share the same future (recommended by checklist item #18).

Comment on lines +20 to +22
CompletableFuture.supplyAsync(() -> {
simulateDelay();
return new UserData(id, "Details for " + id);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This lambda constructs the UserData correctly ("Details for " + id) which matches checklist item #16 — good. However, after the UserData is produced you must store the result into the required Map<String, UserData> cache (checklist item #13). Consider attaching a whenComplete/thenApply handler on the in-flight future to put the finished UserData into cache and remove the entry from the in-flight map.

CompletableFuture.supplyAsync(() -> {
simulateDelay();
return new UserData(id, "Details for " + id);
}, executor)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall: to satisfy all requirements, add a Map<String, UserData> cache = new ConcurrentHashMap<>(); and a separate Map<String, CompletableFuture<UserData>> inFlight = new ConcurrentHashMap<>();. processRequest should (1) return a completed future immediately if cache contains the id, or (2) use inFlight.computeIfAbsent to start or share the async work, then on completion store the resulting UserData into cache. This preserves thread-safety and avoids duplicate expensive operations (addresses checklist items #12, #13 and #18).

Comment thread src/main/java/mate/academy/Main.java Outdated
}

// Wait for all futures to complete
CompletableFuture.allOf(futures).join();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using CompletableFuture.allOf(...).join() and then iterating the futures array prints results in the original input order. The expected output in the task requires cached/fast results to appear earlier — print results as each future completes (e.g., attach a completion handler) or otherwise change the logic to produce the required ordering.

Comment thread src/main/java/mate/academy/Main.java Outdated
CompletableFuture.allOf(futures).join();

for (CompletableFuture<UserData> future : futures) {
System.out.println("Przetworzono: " + future.join());

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Printed prefix is in Polish: "Przetworzono: ". The required exact text is "Processed: " so change this to match the expected console output exactly (checklist item #17 / #7).

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

I am approving your solution as an educational override so you can keep progressing while you refine your understanding of asynchronous execution and thread pools. Your AsyncRequestProcessor is very well done: you correctly use a ConcurrentHashMap for the cache, share in-flight CompletableFutures so duplicate requests don’t trigger extra work, and store results into the cache when processing completes. In Main.java, you correctly iterate over the given userIds array, call processRequest(userId), and print each result with the required "Processed: " prefix as the futures complete.

One important improvement: in src/main/java/mate/academy/Main.java, after submitting all tasks and attaching thenAccept, you call executor.shutdown() immediately, but you don’t wait for completion. This can, in some environments, allow the JVM to exit before all thenAccept callbacks run, so some Processed: ... lines might not print. A good fix would be to either: (1) collect all returned CompletableFuture<UserData> into a list and call CompletableFuture.allOf(list.toArray(...)).join() before shutdown, or (2) call executor.shutdown(); executor.awaitTermination(timeout, unit); to wait for all tasks to finish. Overall, your asynchronous design and caching logic are strong, and with this small lifecycle fix your solution will be robust and production-ready—nice work, keep it up!


✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨

Footnotes

  1. Rate AI review example


// Wait for all futures to complete
CompletableFuture.allOf(futures).join();
executor.shutdown();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling executor.shutdown() immediately may not wait for the submitted asynchronous tasks to finish; the JVM can exit before all thenAccept prints run. Collect the returned CompletableFuture<UserData> instances (e.g., in a list) and wait for them to complete with CompletableFuture.allOf(...).join() or use executor.shutdown(); executor.awaitTermination(...) before exiting to ensure all results are printed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants