Files
kumomta/crates/kcli/src/suspend.rs
T
Wez Furlong eb6232f582 Add basic suspension of scheduled and ready queues
These are two different groups of queues, so there are two different
sets of things to manage them.

kcli now has `suspend(-list|cancel)?` and
`suspend-ready-q(-list|cancel)?` subcommands for establishing a
suspension, listing the suspensions and cancelling a suspension
in the scheduled-q and ready-q namespaces respectively.

The names of the ready queues can be derived from the metrics API:

```console
$ curl -s 'http://localhost:8000/metrics.json'  | jq .
...
  "ready_count": {
    "help": "number of messages in the ready queue",
    "type": "gauge",
    "value": {
      "service": {
        "smtp_client:source2->(in1-smtp|in2-smtp).messagingengine.com": 0.0
      }
    }
  },
...
```

From the above, `source2->(in1-smtp|in2-smtp).messagingengine.com` is
the name of the underlying ready queue.

We can and probably should add something to `kcli` to make that slightly
easier to review and manage for the operator.

refs: https://github.com/KumoCorp/kumomta/issues/51
2023-06-23 07:50:56 -07:00

67 lines
1.9 KiB
Rust

use clap::Parser;
use kumo_api_types::{SuspendV1Request, SuspendV1Response};
use reqwest::Url;
use std::time::Duration;
#[derive(Debug, Parser)]
/// Administratively suspend messages in matching queues.
pub struct SuspendCommand {
/// The domain name to match.
/// If omitted, any domains will match!
#[arg(long)]
domain: Option<String>,
/// The campaign name to match.
/// If omitted, any campaigns will match!
#[arg(long)]
campaign: Option<String>,
/// The tenant name to match.
/// If omitted, any tenant will match!
#[arg(long)]
tenant: Option<String>,
/// The reason to log in the delivery logs
#[arg(long)]
reason: String,
/// Suspend all queues.
#[arg(long)]
everything: bool,
/// The duration over which matching messages will continue to suspend.
/// The default is '5m'.
#[arg(long, value_parser=humantime::parse_duration)]
duration: Option<Duration>,
}
impl SuspendCommand {
pub async fn run(&self, endpoint: &Url) -> anyhow::Result<()> {
if self.domain.is_none() && self.campaign.is_none() && self.tenant.is_none() {
if !self.everything {
anyhow::bail!(
"No domain, campaign or tenant was specified. \
Use --everything if you intend to suspend all queues"
);
}
}
let result: SuspendV1Response = crate::request_with_json_response(
reqwest::Method::POST,
endpoint.join("/api/admin/suspend/v1")?,
&SuspendV1Request {
campaign: self.campaign.clone(),
domain: self.domain.clone(),
tenant: self.tenant.clone(),
reason: self.reason.clone(),
duration: self.duration.clone(),
},
)
.await?;
println!("{}", serde_json::to_string_pretty(&result)?);
Ok(())
}
}