Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,33 @@ If you have any questions or would like to connect, please don't hesitate to rea
</picture>
</p>

---

## Reminder Scheduling Optimization
This logic is implemented in the `ReminderScheduler` and `ReminderRepository`
using scheduled jobs and optimized JPA queries.

### Problem
The application previously scanned all borrow records daily to identify
upcoming due dates, resulting in unnecessary database load and performance
bottlenecks.

### Solution
A dedicated `Reminder` entity is now created when a book is borrowed.
The scheduler queries only reminders that are due on a given date,
eliminating full table scans.

### Key Improvements
- Reduced number of database queries
- Improved performance and scalability
- Cleaner separation of concerns

### Edge Case Handling
- Book renewals update the scheduled reminder date
- Early returns remove pending reminders
- Overdue reminders trigger daily notifications with dynamic fine calculation

---

## Thankyou ❤️
Thank you for taking the time to explore my project. I hope you find them informative and useful in your journey to learn Java and enhance your programming skills. Your support and contributions are highly appreciated.
Expand Down
74 changes: 74 additions & 0 deletions src/main/java/com/libraryman_api/entity/Reminder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.libraryman_api.entity;

import java.time.LocalDate;

import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
/**
* Entity representing a scheduled reminder for borrowed books.
*
* <p>This entity is created at the time of borrowing a book and is used to
* efficiently schedule due-date and overdue notifications without scanning
* all borrow records daily.</p>
*
* <p>Each reminder is triggered on a specific date and marked as sent
* after notification delivery.</p>
*/

@Entity
public class Reminder {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public Long getBorrowingId() {
return borrowingId;
}

public void setBorrowingId(Long borrowingId) {
this.borrowingId = borrowingId;
}

public LocalDate getReminderDate() {
return reminderDate;
}

public void setReminderDate(LocalDate reminderDate) {
this.reminderDate = reminderDate;
}

public boolean isSent() {
return sent;
}

public void setSent(boolean sent) {
this.sent = sent;
}

public ReminderType getType() {
return type;
}

public void setType(ReminderType type) {
this.type = type;
}

private Long borrowingId;
private LocalDate reminderDate;
private boolean sent;

@Enumerated(EnumType.STRING)
private ReminderType type;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
}
11 changes: 11 additions & 0 deletions src/main/java/com/libraryman_api/entity/ReminderType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.libraryman_api.entity;
/**
* Defines the type of reminder to be sent.
*
* DUE_SOON - Reminder sent before the book due date.
* OVERDUE - Daily reminder sent after the due date has passed.
*/
public enum ReminderType {
DUE_SOON,
OVERDUE
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.libraryman_api.repository;

import java.time.LocalDate;
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import com.libraryman_api.entity.Reminder;
/**
* Repository for accessing and managing Reminder entities.
*
* Provides optimized queries to fetch only pending reminders
* scheduled for a specific date.
*/

public interface ReminderRepository extends JpaRepository<Reminder, Long> {
List<Reminder> findByReminderDateAndSentFalse(LocalDate date);
}
48 changes: 48 additions & 0 deletions src/main/java/com/libraryman_api/scheduler/ReminderScheduler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.libraryman_api.scheduler;

import java.time.LocalDate;
import java.util.List;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.libraryman_api.entity.Reminder;
import com.libraryman_api.repository.ReminderRepository;

@Component
/**
* Scheduler responsible for sending due-date and overdue book reminders.
*
* <p>This scheduler queries only the reminders that are due on the current
* date, avoiding full table scans of borrowing records and significantly
* improving system performance.</p>
*/

public class ReminderScheduler {

private final ReminderRepository reminderRepository;
public ReminderScheduler(ReminderRepository reminderRepository) {
this.reminderRepository = reminderRepository;
}
/**
* Sends reminders scheduled for the current date.
*
* <p>Executed daily at 9 AM to process pending reminders and mark them
* as sent after successful notification delivery.</p>
*/

@Scheduled(cron = "0 0 9 * * ?")
public void sendDueReminders() {

LocalDate today = LocalDate.now();
List<Reminder> reminders =
reminderRepository.findByReminderDateAndSentFalse(today);

for (Reminder reminder : reminders) {
// call notification logic
reminder.setSent(true);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

reminderRepository.saveAll(reminders);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Loading