Reschedule the reminders when adding a new one
The thread handling the reminders is unparked and reschedules the execution of sending out reminders.
This commit is contained in:
parent
7ded3ef430
commit
a4a1234f06
4 changed files with 61 additions and 32 deletions
|
@ -4,4 +4,5 @@ rustflags = [
|
||||||
"-Dclippy::pedantic",
|
"-Dclippy::pedantic",
|
||||||
"-Dclippy::nursery",
|
"-Dclippy::nursery",
|
||||||
"-Dclippy::cargo",
|
"-Dclippy::cargo",
|
||||||
|
"-Aclippy::multiple-crate-versions",
|
||||||
]
|
]
|
||||||
|
|
54
Cargo.lock
generated
54
Cargo.lock
generated
|
@ -348,9 +348,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.4.0"
|
version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
|
@ -466,12 +466,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-lifetimes"
|
name = "io-lifetimes"
|
||||||
version = "1.0.4"
|
version = "1.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
|
checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -483,7 +483,7 @@ dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"io-lifetimes",
|
"io-lifetimes",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -592,7 +592,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wasi",
|
"wasi",
|
||||||
"windows-sys",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -727,15 +727,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot_core"
|
name = "parking_lot_core"
|
||||||
version = "0.9.6"
|
version = "0.9.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf"
|
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-sys",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -890,7 +890,7 @@ dependencies = [
|
||||||
"io-lifetimes",
|
"io-lifetimes",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -911,7 +911,7 @@ version = "0.1.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
|
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1075,9 +1075,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sync_wrapper"
|
name = "sync_wrapper"
|
||||||
version = "0.1.1"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8"
|
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
|
@ -1190,7 +1190,7 @@ dependencies = [
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1472,6 +1472,30 @@ dependencies = [
|
||||||
"windows_x86_64_msvc",
|
"windows_x86_64_msvc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.45.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.42.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.42.1"
|
version = "0.42.1"
|
||||||
|
|
18
src/api.rs
18
src/api.rs
|
@ -1,4 +1,4 @@
|
||||||
use crate::{schema, NewReminder};
|
use crate::{schema, AppState, NewReminder};
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::State,
|
extract::State,
|
||||||
|
@ -6,10 +6,7 @@ use axum::{
|
||||||
response::{IntoResponse, Response, Result},
|
response::{IntoResponse, Response, Result},
|
||||||
Json,
|
Json,
|
||||||
};
|
};
|
||||||
use diesel::{
|
use diesel::prelude::*;
|
||||||
prelude::*,
|
|
||||||
r2d2::{ConnectionManager, Pool},
|
|
||||||
};
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
use tracing::{error, trace};
|
use tracing::{error, trace};
|
||||||
|
@ -33,7 +30,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct CreateReminder {
|
pub struct Reminder {
|
||||||
#[serde(with = "time::serde::iso8601")]
|
#[serde(with = "time::serde::iso8601")]
|
||||||
planned: OffsetDateTime,
|
planned: OffsetDateTime,
|
||||||
title: String,
|
title: String,
|
||||||
|
@ -43,8 +40,8 @@ pub struct CreateReminder {
|
||||||
|
|
||||||
#[allow(clippy::unused_async)]
|
#[allow(clippy::unused_async)]
|
||||||
pub async fn create_reminder(
|
pub async fn create_reminder(
|
||||||
State(db_pool): State<Pool<ConnectionManager<PgConnection>>>,
|
State(state): State<AppState>,
|
||||||
Json(data): Json<CreateReminder>,
|
Json(data): Json<Reminder>,
|
||||||
) -> Result<impl IntoResponse, ServerError> {
|
) -> Result<impl IntoResponse, ServerError> {
|
||||||
let reminder = NewReminder {
|
let reminder = NewReminder {
|
||||||
created: OffsetDateTime::now_utc(),
|
created: OffsetDateTime::now_utc(),
|
||||||
|
@ -58,7 +55,10 @@ pub async fn create_reminder(
|
||||||
|
|
||||||
diesel::insert_into(schema::reminders::table)
|
diesel::insert_into(schema::reminders::table)
|
||||||
.values(&reminder)
|
.values(&reminder)
|
||||||
.execute(&mut db_pool.get()?)?;
|
.execute(&mut state.db_pool.get()?)?;
|
||||||
|
|
||||||
|
trace!("unpark reminder thread to reschedule next run");
|
||||||
|
state.reminder.thread().unpark();
|
||||||
|
|
||||||
Ok((StatusCode::CREATED, "Reminder created".to_string()))
|
Ok((StatusCode::CREATED, "Reminder created".to_string()))
|
||||||
}
|
}
|
||||||
|
|
20
src/main.rs
20
src/main.rs
|
@ -6,7 +6,7 @@ use diesel::{
|
||||||
r2d2::{ConnectionManager, Pool},
|
r2d2::{ConnectionManager, Pool},
|
||||||
};
|
};
|
||||||
use lettre::{Message, SmtpTransport, Transport};
|
use lettre::{Message, SmtpTransport, Transport};
|
||||||
use std::{env, net::SocketAddr, time::Duration};
|
use std::{env, net::SocketAddr, sync::Arc, thread::JoinHandle, time::Duration};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
use tower::ServiceBuilder;
|
use tower::ServiceBuilder;
|
||||||
use tower_http::trace::TraceLayer;
|
use tower_http::trace::TraceLayer;
|
||||||
|
@ -80,6 +80,12 @@ fn remind(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct AppState {
|
||||||
|
db_pool: Pool<ConnectionManager<PgConnection>>,
|
||||||
|
reminder: Arc<JoinHandle<Result<(), Error>>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
@ -97,25 +103,23 @@ async fn main() -> Result<()> {
|
||||||
);
|
);
|
||||||
|
|
||||||
let config = Config::load_config(args.config)?;
|
let config = Config::load_config(args.config)?;
|
||||||
|
|
||||||
let mut db_pool = get_connection_pool(&config)?;
|
let mut db_pool = get_connection_pool(&config)?;
|
||||||
|
let reminder = std::thread::spawn(move || -> Result<(), Error> {
|
||||||
std::thread::spawn(move || -> Result<(), Error> {
|
|
||||||
let mailer = SmtpTransport::unencrypted_localhost();
|
let mailer = SmtpTransport::unencrypted_localhost();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
remind(&mut db_pool, &mailer)?;
|
remind(&mut db_pool, &mailer)?;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let db_pool = get_connection_pool(&config)?;
|
let db_pool = get_connection_pool(&config)?;
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/v1/reminder", post(api::create_reminder))
|
.route("/v1/reminder", post(api::create_reminder))
|
||||||
.layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()))
|
.layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()))
|
||||||
.fallback(api::not_found)
|
.fallback(api::not_found)
|
||||||
.with_state(db_pool);
|
.with_state(AppState {
|
||||||
|
db_pool,
|
||||||
|
reminder: Arc::new(reminder),
|
||||||
|
});
|
||||||
let addr = SocketAddr::from((config.server.address, config.server.port));
|
let addr = SocketAddr::from((config.server.address, config.server.port));
|
||||||
|
|
||||||
info!("{} listening on {}", env!("CARGO_PKG_NAME"), addr);
|
info!("{} listening on {}", env!("CARGO_PKG_NAME"), addr);
|
||||||
|
|
Loading…
Reference in a new issue