Added queue backpressure event
This commit is contained in:
@@ -137,15 +137,34 @@ cert = '%{file:{CERT}}%'
|
||||
private-key = '%{file:{PK}}%'
|
||||
|
||||
[storage]
|
||||
data = "rocksdb"
|
||||
lookup = "rocksdb"
|
||||
blob = "rocksdb"
|
||||
fts = "rocksdb"
|
||||
data = "{STORE}"
|
||||
fts = "{STORE}"
|
||||
blob = "{STORE}"
|
||||
lookup = "{STORE}"
|
||||
|
||||
[store."rocksdb"]
|
||||
type = "rocksdb"
|
||||
path = "{TMP}/queue.db"
|
||||
|
||||
[store."foundationdb"]
|
||||
type = "foundationdb"
|
||||
|
||||
[store."postgresql"]
|
||||
type = "postgresql"
|
||||
host = "localhost"
|
||||
port = 5432
|
||||
database = "stalwart"
|
||||
user = "postgres"
|
||||
password = "mysecretpassword"
|
||||
|
||||
[store."mysql"]
|
||||
type = "mysql"
|
||||
host = "localhost"
|
||||
port = 3307
|
||||
database = "stalwart"
|
||||
user = "root"
|
||||
password = "password"
|
||||
|
||||
"#;
|
||||
|
||||
impl TestSMTP {
|
||||
@@ -198,9 +217,21 @@ impl TestSMTP {
|
||||
}
|
||||
|
||||
pub async fn new(name: &str, config: impl AsRef<str>) -> TestSMTP {
|
||||
Self::with_database(name, config, "rocksdb").await
|
||||
}
|
||||
|
||||
pub async fn with_database(
|
||||
name: &str,
|
||||
config: impl AsRef<str>,
|
||||
store_id: impl AsRef<str>,
|
||||
) -> TestSMTP {
|
||||
let temp_dir = TempDir::new(name, true);
|
||||
let mut config =
|
||||
Config::new(temp_dir.update_config(add_test_certs(CONFIG) + config.as_ref())).unwrap();
|
||||
let mut config = Config::new(
|
||||
temp_dir
|
||||
.update_config(add_test_certs(CONFIG) + config.as_ref())
|
||||
.replace("{STORE}", store_id.as_ref()),
|
||||
)
|
||||
.unwrap();
|
||||
config.resolve_all_macros().await;
|
||||
let stores = Stores::parse_all(&mut config, false).await;
|
||||
let core = Core::parse(&mut config, stores, Default::default()).await;
|
||||
|
||||
@@ -23,8 +23,12 @@ relay = true
|
||||
messages = 2000
|
||||
|
||||
[queue.outbound]
|
||||
concurrency = 1
|
||||
concurrency = 4
|
||||
|
||||
[queue.schedule]
|
||||
retry = "1s"
|
||||
notify = "1d"
|
||||
expire = "1d"
|
||||
"#;
|
||||
|
||||
const REMOTE: &str = r#"
|
||||
@@ -39,7 +43,10 @@ enable = false
|
||||
|
||||
"#;
|
||||
|
||||
#[tokio::test]
|
||||
const NUM_MESSAGES: usize = 1000;
|
||||
const NUM_QUEUES: usize = 10;
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 18)]
|
||||
#[serial_test::serial]
|
||||
async fn concurrent_queue() {
|
||||
// Enable logging
|
||||
@@ -49,7 +56,7 @@ async fn concurrent_queue() {
|
||||
let remote = TestSMTP::new("smtp_concurrent_queue_remote", REMOTE).await;
|
||||
let _rx = remote.start(&[ServerProtocol::Smtp]).await;
|
||||
|
||||
let local = TestSMTP::new("smtp_concurrent_queue_local", LOCAL).await;
|
||||
let local = TestSMTP::with_database("smtp_concurrent_queue_local", LOCAL, "mysql").await;
|
||||
|
||||
// Add mock DNS entries
|
||||
let core = local.build_smtp();
|
||||
@@ -72,9 +79,9 @@ async fn concurrent_queue() {
|
||||
session.eval_session_params().await;
|
||||
session.ehlo("mx.test.org").await;
|
||||
|
||||
// Spawn 20 concurrent queues
|
||||
// Spawn concurrent queues
|
||||
let mut inners = vec![];
|
||||
for _ in 0..20 {
|
||||
for _ in 0..NUM_QUEUES {
|
||||
let (inner, rxs) = local.inner_with_rxs();
|
||||
let server = inner.build_server();
|
||||
server.mx_add(
|
||||
@@ -99,9 +106,9 @@ async fn concurrent_queue() {
|
||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||
|
||||
// Send 1000 test messages
|
||||
for _ in 0..100 {
|
||||
for _ in 0..(NUM_MESSAGES / 2) {
|
||||
session
|
||||
.send_message("john@test.org", &["bill@foobar.org"], "test:no_dkim", "250")
|
||||
.send_message("john@test.org", &["slow@foobar.org"], "test:no_dkim", "250")
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -109,12 +116,41 @@ async fn concurrent_queue() {
|
||||
for inner in &inners {
|
||||
inner.ipc.queue_tx.send(QueueEvent::Refresh).await.unwrap();
|
||||
}
|
||||
for _ in 0..(NUM_MESSAGES / 2) {
|
||||
session
|
||||
.send_message(
|
||||
"john@test.org",
|
||||
&["delay-random@foobar.org"],
|
||||
"test:no_dkim",
|
||||
"250",
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(1500)).await;
|
||||
loop {
|
||||
tokio::time::sleep(Duration::from_millis(1500)).await;
|
||||
|
||||
let m = local.queue_receiver.read_queued_messages().await.len();
|
||||
let e = local.queue_receiver.read_queued_events().await.len();
|
||||
|
||||
if m + e != 0 {
|
||||
println!("Queue still has {} messages and {} events", m, e);
|
||||
for inner in &inners {
|
||||
inner
|
||||
.ipc
|
||||
.queue_tx
|
||||
.send(QueueEvent::Paused(true))
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
local.queue_receiver.assert_queue_is_empty().await;
|
||||
let remote_messages = remote.queue_receiver.read_queued_messages().await;
|
||||
assert_eq!(remote_messages.len(), 100);
|
||||
assert_eq!(remote_messages.len(), NUM_MESSAGES);
|
||||
|
||||
// Make sure local store is queue
|
||||
core.core
|
||||
|
||||
Reference in New Issue
Block a user