Skip to content

Commit 031b1dd

Browse files
0xPoeTurbo87
authored andcommitted
feat: only query 10000 tokens
Signed-off-by: hi-rustin <[email protected]>
1 parent dd966b5 commit 031b1dd

File tree

1 file changed

+32
-25
lines changed

1 file changed

+32
-25
lines changed

src/worker/jobs/expiry_notification.rs

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ use std::sync::Arc;
1414
/// The threshold in days for the expiry notification.
1515
const EXPIRY_THRESHOLD: chrono::TimeDelta = chrono::TimeDelta::days(3);
1616

17+
/// The maximum number of tokens to check.
18+
/// To avoid sending too many emails and submitting to many transactions, we limit the number of
19+
/// tokens to check.
20+
const MAX_ROWS: i64 = 10000;
21+
1722
/// A job responsible for monitoring the status of a token.
1823
/// It checks if the token is about to reach its expiry date.
1924
/// If the token is about to expire, the job triggers a notification.
@@ -37,35 +42,36 @@ impl BackgroundJob for CheckAboutToExpireToken {
3742
.map_err(|err| anyhow!(err.to_string()))?
3843
}
3944
}
45+
4046
// Check if the token is about to expire and send a notification if it is.
4147
fn check(emails: &Emails, conn: &mut PgConnection) -> anyhow::Result<()> {
4248
info!("Checking if tokens are about to expire");
4349
let expired_tokens = find_tokens_expiring_within_days(conn, EXPIRY_THRESHOLD)?;
44-
// Batch send notifications in transactions.
45-
const BATCH_SIZE: usize = 100;
46-
for chunk in expired_tokens.chunks(BATCH_SIZE) {
50+
if expired_tokens.len() == MAX_ROWS as usize {
51+
warn!("The maximum number of API tokens per query has been reached. More API tokens might be processed on the next run.");
52+
}
53+
for token in &expired_tokens {
4754
conn.transaction(|conn| {
48-
for token in chunk {
49-
// Send notification.
50-
let user = User::find(conn, token.user_id)?;
51-
let Some(recipient) = user.email(conn)? else {
52-
return Err(anyhow!("No address found"));
53-
};
54-
let email = ExpiryNotificationEmail {
55-
name: &user.gh_login,
56-
token_name: &token.name,
57-
expiry_date: token.expired_at.unwrap().and_utc(),
58-
};
59-
match emails.send(&recipient, email) {
60-
Ok(_) => {
61-
// Update the token to prevent duplicate notifications.
62-
diesel::update(token)
63-
.set(api_tokens::expiry_notification_at.eq(now.nullable()))
64-
.execute(conn)?;
65-
}
66-
Err(e) => {
67-
error!("Failed to send email: {:?} to {}", e, recipient);
68-
}
55+
// Send notification.
56+
let user = User::find(conn, token.user_id)?;
57+
let Some(recipient) = user.email(conn)? else {
58+
return Err(anyhow!("No address found"));
59+
};
60+
let email = ExpiryNotificationEmail {
61+
name: &user.gh_login,
62+
token_name: &token.name,
63+
expiry_date: token.expired_at.unwrap().and_utc(),
64+
};
65+
match emails.send(&recipient, email) {
66+
Ok(_) => {
67+
// Update the token to prevent duplicate notifications.
68+
diesel::update(token)
69+
.set(api_tokens::expiry_notification_at.eq(now.nullable()))
70+
.execute(conn)?;
71+
}
72+
Err(e) => {
73+
error!(?e, ?recipient, "Failed to send notification");
74+
return Err(anyhow!("Failed to send notification: {}", e));
6975
}
7076
}
7177
Ok::<_, anyhow::Error>(())
@@ -74,7 +80,6 @@ fn check(emails: &Emails, conn: &mut PgConnection) -> anyhow::Result<()> {
7480

7581
Ok(())
7682
}
77-
7883
/// Find all tokens that are not revoked and will expire within the specified number of days.
7984
pub fn find_tokens_expiring_within_days(
8085
conn: &mut PgConnection,
@@ -94,6 +99,8 @@ pub fn find_tokens_expiring_within_days(
9499
)
95100
.filter(api_tokens::expiry_notification_at.is_null())
96101
.select(ApiToken::as_select())
102+
.order_by(api_tokens::expired_at.asc()) // The most urgent tokens first
103+
.limit(MAX_ROWS)
97104
.get_results(conn)
98105
}
99106

0 commit comments

Comments
 (0)