feat(k8s): add Kubernetes Helm chart for emailks service
- Create Helm chart structure with Chart.yaml and values.yaml - Add deployment template with container configuration and environment variables - Implement service template for gRPC port exposure - Add service account template with security configuration - Include horizontal pod autoscaler template for scaling capabilities - Add helper templates for naming and label management - Configure SMTP settings as configurable parameters in values.yaml - Set up resource limits and requests for container performance - Implement liveness and readiness probes for health checks - Add support for existing secrets and custom configurations
This commit is contained in:
@@ -8,6 +8,8 @@ use tonic::{Request, Response, Status};
|
||||
use tracing::warn;
|
||||
|
||||
const STREAM_STATUS_POLL_INTERVAL: Duration = Duration::from_millis(300);
|
||||
/// Maximum lifetime of a single streaming batch-status RPC.
|
||||
/// Protects against leaked streams when jobs never reach a terminal state.
|
||||
const STREAM_STATUS_TIMEOUT: Duration = Duration::from_secs(10 * 60);
|
||||
|
||||
use crate::{
|
||||
@@ -75,12 +77,12 @@ impl EmailService for EmailServiceImpl {
|
||||
request: Request<BatchSendEmailRequest>,
|
||||
) -> Result<Response<BatchSendEmailResponse>, Status> {
|
||||
let req = request.into_inner();
|
||||
let total = req.emails.len();
|
||||
let total = req.emails.len() as i32;
|
||||
let mut success = 0i32;
|
||||
let mut failures = 0i32;
|
||||
let mut results = Vec::with_capacity(total);
|
||||
let mut results = Vec::with_capacity(total as usize);
|
||||
|
||||
for email in req.emails {
|
||||
for (i, email) in req.emails.into_iter().enumerate() {
|
||||
match self.queue.enqueue(email) {
|
||||
Ok(id) => {
|
||||
success += 1;
|
||||
@@ -90,6 +92,8 @@ impl EmailService for EmailServiceImpl {
|
||||
failures += 1;
|
||||
warn!(%e, "batch enqueue failed for one email");
|
||||
if req.fail_fast {
|
||||
// Count remaining unprocessed emails as failures too.
|
||||
failures += total - (i as i32) - 1;
|
||||
warn!(
|
||||
successful = success,
|
||||
failed = failures,
|
||||
@@ -152,6 +156,7 @@ impl EmailService for EmailServiceImpl {
|
||||
|
||||
let id_set: std::collections::HashSet<u64> = ids.iter().copied().collect();
|
||||
let store = self.store.clone();
|
||||
let mut missing_streak: std::collections::HashMap<u64, u32> = std::collections::HashMap::new();
|
||||
let (tx, rx) = mpsc::channel(ids.len().saturating_add(immediate_results.len()).max(1));
|
||||
|
||||
tokio::spawn(async move {
|
||||
@@ -186,6 +191,7 @@ impl EmailService for EmailServiceImpl {
|
||||
continue;
|
||||
}
|
||||
if let Some(entry) = store.get(*id) {
|
||||
missing_streak.remove(id);
|
||||
match entry.status {
|
||||
SendStatus::Sent => {
|
||||
if tx
|
||||
@@ -209,6 +215,20 @@ impl EmailService for EmailServiceImpl {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
// Status entry may have been evicted under memory pressure.
|
||||
// Report as failed after a few consecutive misses.
|
||||
let streak = missing_streak.entry(*id).and_modify(|c| *c += 1).or_insert(1);
|
||||
if *streak >= 5 {
|
||||
if tx.send(Ok(build_failed_response(
|
||||
Some(*id),
|
||||
"status entry evicted before terminal state".into(),
|
||||
))).await.is_err() {
|
||||
return;
|
||||
}
|
||||
reported.insert(*id);
|
||||
missing_streak.remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user