milestone: add runtime template state and dlq/retry broker topology

This commit is contained in:
2026-04-06 18:41:17 -07:00
parent 836a968806
commit 516a740505
12 changed files with 838 additions and 273 deletions

View File

@@ -21,7 +21,9 @@ use lapin::{
BasicProperties,
};
use rustybeds::brokers;
use rustybeds::brokers::payload::ENVELOPE_VERSION;
use rustybeds::services::amqp::{AmqpConnection, EXCHANGE_NAME};
use rustybeds::template_registry::{RuntimeTemplateRegistry, load_runtime_rec_templates};
/// Attempts to connect to the test broker. Returns None if unreachable so
/// tests can skip rather than fail when RabbitMQ is not running locally.
@@ -77,12 +79,20 @@ async fn ping_round_trip(channel: &lapin::Channel, routing_key: &str, expected_b
.with_reply_to(reply_queue.clone().into())
.with_correlation_id(correlation_id.clone().into());
let body = serde_json::json!({
"version": ENVELOPE_VERSION,
"op": "ping",
"template": "Logger",
"correlation_id": correlation_id,
"payload": {},
});
channel
.basic_publish(
EXCHANGE_NAME,
routing_key,
BasicPublishOptions::default(),
b"{}",
&serde_json::to_vec(&body).expect("failed to encode ping envelope"),
props,
)
.await
@@ -99,8 +109,10 @@ async fn ping_round_trip(channel: &lapin::Channel, routing_key: &str, expected_b
let payload: serde_json::Value =
serde_json::from_slice(&delivery.data).expect("reply payload is not valid JSON");
assert_eq!(payload["version"], ENVELOPE_VERSION);
assert_eq!(payload["status"], "ok");
assert_eq!(payload["broker"], expected_broker);
assert_eq!(payload["op"], "ping");
assert_eq!(payload["payload"]["broker"], expected_broker);
if let Some(cid) = delivery.properties.correlation_id().as_ref() {
assert_eq!(cid.as_str(), correlation_id);
@@ -207,12 +219,20 @@ async fn r_and_w_brokers_process_ping_events() {
.await
.expect("exchange declaration failed");
let mut handles = brokers::spawn_r_broker_pool(Arc::clone(&conn), &cfg.broker_services)
let template_registry = std::sync::Arc::new(RuntimeTemplateRegistry::from_templates(
load_runtime_rec_templates("templates").expect("template load failed"),
));
let mut handles = brokers::spawn_r_broker_pool(
Arc::clone(&conn),
&cfg.broker_services,
std::sync::Arc::clone(&template_registry),
)
.await
.expect("rBroker pool failed to start");
handles.extend(
brokers::spawn_w_broker_pool(Arc::clone(&conn), &cfg.broker_services)
brokers::spawn_w_broker_pool(Arc::clone(&conn), &cfg.broker_services, std::sync::Arc::clone(&template_registry))
.await
.expect("wBroker pool failed to start"),
);
@@ -254,12 +274,20 @@ async fn logger_write_then_fetch_round_trip() {
.await
.expect("exchange declaration failed");
let mut handles = brokers::spawn_r_broker_pool(Arc::clone(&conn), &cfg.broker_services)
let template_registry = std::sync::Arc::new(RuntimeTemplateRegistry::from_templates(
load_runtime_rec_templates("templates").expect("template load failed"),
));
let mut handles = brokers::spawn_r_broker_pool(
Arc::clone(&conn),
&cfg.broker_services,
std::sync::Arc::clone(&template_registry),
)
.await
.expect("rBroker pool failed to start");
handles.extend(
brokers::spawn_w_broker_pool(Arc::clone(&conn), &cfg.broker_services)
brokers::spawn_w_broker_pool(Arc::clone(&conn), &cfg.broker_services, std::sync::Arc::clone(&template_registry))
.await
.expect("wBroker pool failed to start"),
);
@@ -270,8 +298,11 @@ async fn logger_write_then_fetch_round_trip() {
.expect("failed to create test channel");
let write_request = serde_json::json!({
"version": ENVELOPE_VERSION,
"op": "write",
"template": "Logger",
"data": {
"correlation_id": "logger-write-1",
"payload": {
"message_log": "poc-log-message",
"level_log": "info",
"service_log": "app_server"
@@ -280,20 +311,27 @@ async fn logger_write_then_fetch_round_trip() {
let write_reply = request_reply_json(&test_channel, "rec.write", "write", write_request).await;
assert_eq!(write_reply["status"], "ok");
assert_eq!(write_reply["code"], "LOGGER_WRITE");
assert_eq!(write_reply["version"], ENVELOPE_VERSION);
assert_eq!(write_reply["op"], "write");
assert_eq!(write_reply["payload"]["code"], "LOGGER_WRITE");
let fetch_request = serde_json::json!({
"version": ENVELOPE_VERSION,
"op": "fetch",
"template": "Logger",
"data": {
"correlation_id": "logger-fetch-1",
"payload": {
"limit": 10
}
});
let fetch_reply = request_reply_json(&test_channel, "rec.read", "fetch", fetch_request).await;
assert_eq!(fetch_reply["status"], "ok");
assert_eq!(fetch_reply["code"], "LOGGER_FETCH");
assert_eq!(fetch_reply["version"], ENVELOPE_VERSION);
assert_eq!(fetch_reply["op"], "fetch");
assert_eq!(fetch_reply["payload"]["code"], "LOGGER_FETCH");
let logs = fetch_reply["logs"].as_array().expect("logs must be an array");
let logs = fetch_reply["payload"]["logs"].as_array().expect("logs must be an array");
assert!(
logs.iter().any(|v| v["message_log"] == "poc-log-message"),
"fetched logs should include the message just written"