Skip to content

Conversation

@matthijsln
Copy link
Contributor

@matthijsln matthijsln commented Dec 10, 2025

HTM-1820 Powered by Pull Request Badge

Do not immediately shut down the ExecutorService after creating and submitting a task.

@matthijsln matthijsln requested a review from mprins December 10, 2025 10:42
@matthijsln matthijsln added the bug Something isn't working label Dec 10, 2025
@codecov
Copy link

codecov bot commented Dec 10, 2025

Codecov Report

❌ Patch coverage is 0% with 40 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...ilormap/api/service/PasswordResetEmailService.java 0% 27 Missing ⚠️
...a/org/tailormap/api/configuration/AsyncConfig.java 0% 8 Missing ⚠️
...lormap/api/controller/PasswordResetController.java 0% 5 Missing ⚠️

Impacted file tree graph

@@           Coverage Diff            @@
##             main   #1534     +/-   ##
========================================
- Coverage      77%      4%    -73%     
  Complexity    105     105             
========================================
  Files         151     153      +2     
  Lines        7576    7582      +6     
  Branches      690     691      +1     
========================================
- Hits         5815     267   -5548     
- Misses       1361    7296   +5935     
+ Partials      400      19    -381     
Files with missing lines Coverage Δ Complexity Δ
...lormap/api/controller/PasswordResetController.java 0% <0%> (-80%) 0 <0> (ø)
...a/org/tailormap/api/configuration/AsyncConfig.java 0% <0%> (ø) 0 <0> (?)
...ilormap/api/service/PasswordResetEmailService.java 0% <0%> (ø) 0 <0> (?)

... and 138 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@matthijsln matthijsln changed the title Fix blocking when sending a password-reset email HTM-1820: Fix blocking when sending a password-reset email Dec 10, 2025
@github-actions
Copy link

github-actions bot commented Dec 10, 2025

Test Results

0 files   -  51  0 suites   - 51   0s ⏱️ - 5m 26s
0 tests  - 454  0 ✅  - 453  0 💤  - 1  0 ❌ ±0 
0 runs   - 448  0 ✅  - 447  0 💤  - 1  0 ❌ ±0 

Results for commit a641c07. ± Comparison against base commit 5056292.

♻️ This comment has been updated with latest results.

@matthijsln matthijsln force-pushed the password-reset-dont-block-send branch from c990402 to 598020b Compare December 10, 2025 10:55
…shut down ExecutorService after creating and submitting a task)
Copy link
Contributor

@mprins mprins left a comment

Choose a reason for hiding this comment

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

tests are failing:

Parameter 0 of constructor in org.tailormap.api.service.PasswordResetEmailService required a bean of type 'org.springframework.mail.javamail.JavaMailSender' that could not be found.

@mprins mprins marked this pull request as draft December 11, 2025 10:21
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a blocking issue in the password reset email functionality by replacing manual ExecutorService management with Spring's built-in async support. The original implementation immediately shut down the ExecutorService after submitting tasks, which prevented email sending from completing.

Key changes:

  • Introduced Spring's @EnableAsync configuration with a dedicated ThreadPoolTaskExecutor for password reset emails
  • Extracted email sending logic into a new PasswordResetEmailService with @async method
  • Removed manual ExecutorService creation and management from PasswordResetController

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/main/java/org/tailormap/api/configuration/AsyncConfig.java New configuration class that enables async support and defines a dedicated ThreadPoolTaskExecutor bean for password reset operations
src/main/java/org/tailormap/api/service/PasswordResetEmailService.java New service class that encapsulates password reset email sending logic with @async annotation for proper async execution
src/main/java/org/tailormap/api/controller/PasswordResetController.java Refactored to delegate email sending to the new PasswordResetEmailService, removing manual ExecutorService management and related dependencies

Comment on lines +48 to +74
public void sendPasswordResetEmailAsync(
String email, String absoluteLinkPrefix, Locale locale, int tokenExpiryMinutes) {
try {
User user = userRepository.findByEmail(email).orElse(null);
if (user == null || !user.isEnabledAndValidUntil()) {
return;
}

TemporaryToken token =
new TemporaryToken(TemporaryToken.TokenType.PASSWORD_RESET, user.getUsername(), tokenExpiryMinutes);
token = temporaryTokenRepository.save(token);

String absoluteLink =
absoluteLinkPrefix + "/user/password-reset/" + token.getCombinedTokenAndExpirationAsBase64();

SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(mailFrom);
message.setTo(user.getEmail());
message.setSubject(messageSource.getMessage("reset-password-request.email-subject", null, locale));
message.setText(
messageSource.getMessage("reset-password-request.email-body", new Object[] {absoluteLink}, locale));

logger.info("Sending password reset email for user: {}", user.getUsername());
emailSender.send(message); // blocking, but run in async thread
} catch (Exception e) {
logger.error("Failed to send password reset email", e);
}
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

The async method performs database operations (userRepository.findByEmail and temporaryTokenRepository.save) without @transactional annotation. When running in a separate thread, these operations may not have proper transaction boundaries, which could lead to connection leaks or unexpected behavior. Consider adding @transactional annotation to this method to ensure proper transaction management in the async context.

Copilot uses AI. Check for mistakes.
executor.setCorePoolSize(1);
executor.setMaxPoolSize(1);
executor.setQueueCapacity(10);
executor.setThreadNamePrefix("pwd-reset-");
Copy link

Copilot AI Dec 11, 2025

Choose a reason for hiding this comment

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

The AsyncConfig should configure setWaitForTasksToCompleteOnShutdown(true) and setAwaitTerminationSeconds to ensure graceful shutdown. Without this, pending password reset emails might not be sent when the application shuts down, potentially leaving users without the ability to reset their passwords. This is especially important given the queue capacity of 10.

Suggested change
executor.setThreadNamePrefix("pwd-reset-");
executor.setThreadNamePrefix("pwd-reset-");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(30);

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants