Rust

Crate-ul honk-me este un client async pe Tokio și reqwest cu rustls, deci fără OpenSSL. Feature-ul blocking adaugă un client sincron pentru scripturi și CLI-uri.

Pachet
honk-me Publicat
Cod sursă
github.com/honk-me/honk-rust · Licență MIT
Cerințe
Rust 1.85 sau mai nou.

Instalare

Pentru cod sincron: cargo add honk-me --features blocking.

Terminal
cargo add honk-me
cargo add tokio --features macros,rt-multi-thread   # if you don't have a runtime yet

Oricine are o cheie API (honk_…) poate trimite mesaje în proiectul ei. Ține-o pe servere, în joburi și în secretele din CI, niciodată într-o aplicație de browser, de mobil sau de desktop.

Trimite un eveniment

Sau explicit: Honk::new("https://honk-me.app", key)?. Honk se clonează ieftin: creează unul și folosește-l peste tot, ca să rămână conexiunile deschise.

use honk_me::Honk;

#[tokio::main]
async fn main() -> honk_me::Result<()> {
    let honk = Honk::from_env()?; // HONK_URL, HONK_KEY (+ HONK_SOURCE, HONK_ENVIRONMENT, HONK_CHANNEL)
    honk.beep("Backup finished", "nightly pg_dump took 42 s").await?;
    Ok(())
}

Rețetă: cererea unui client, direct pe telefon

Un grup pentru fiecare cerere și propria ta cheie de idempotență, ca un webhook retrimis să nu te anunțe niciodată de două ori.

use honk_me::{Category, Message, Priority, Severity};

let msg = Message::new(format!("{} asked for a quote: {}", req.name, req.summary))
    .title("New quote request")
    .severity(Severity::LOUD)
    .priority(Priority::High)
    .category(Category::Customers)
    .group_key(format!("requests/{}", req.id))
    .url(format!("https://shop.example.com/admin/requests/{}", req.id)); // https only, "Open link"
honk.send(&msg, format!("request-{}", req.id).as_str()).await?;

Scala Honk și incidentele

Fiecare helper întoarce un PendingSend: adaugă alte câmpuri în lanț, apoi fă .await.

use honk_me::Priority;

honk.loud("Disk 91% full", "db-1 /var is at 91%")
    .group_key("disk/db-1/var")
    .priority(Priority::High)
    .metadata("used_percent", 91)
    .await?;

honk.problem("db/backup", "Backup failed", "pg_dump exited with 1").await?;
honk.recovery("db/backup", "Backup OK", "pg_dump finished").await?;

Clientul blocant

Rulează clientul async pe un runtime privat, cu un singur fir de execuție, cu aceleași reîncercări. Nu-l apela din interiorul unui runtime async.

// Cargo.toml: honk-me = { version = "0.2", features = ["blocking"] }
use honk_me::blocking::Honk;

let honk = Honk::from_env()?;
honk.beep("Backup finished", "nightly pg_dump took 42 s").send()?;
honk.send(&honk_me::Message::new("Imported 1 204 rows"), None)?;

Erori

Fiecare variantă Error are un Failure cu statusul, codul, fiecare câmp invalid și retry_after.

use honk_me::Error;

match honk.send(&msg, "order-1042-failed").await {
    Ok(_) => {}
    Err(Error::Validation(f)) => tracing::error!(?f.fields, "a bug: don't retry"),
    Err(e) if e.is_retryable() => queue.retry_later(e.idempotency_key(), e.retry_after()),
    Err(e) => return Err(e.into()),
}

Reîncercări care nu trimit nimic de două ori

  • Fiecare trimitere are un Idempotency-Key: al tău sau un UUIDv7 nou. Aceeași cheie e refolosită la fiecare reîncercare, iar timp de 24 de ore Honk răspunde la o repetare cu id-ul original și duplicate: true, așa că un răspuns pierdut nu creează niciodată un al doilea mesaj.
  • Se reîncearcă doar erorile de rețea, cererile care expiră, 429 și 5xx, cu backoff exponențial și jitter complet, niciodată mai devreme decât Retry-After de la server. Celelalte răspunsuri 4xx nu se reîncearcă niciodată: corectează cererea.
  • Fiecare încercare expiră după 5 secunde, iar totul se oprește după 30. Dacă ar trebui să aștepte mai mult, de exemplu până se resetează cota zilnică la miezul nopții, eșuează imediat și îți spune când să reîncerci.
  • Câmpurile sunt verificate înainte de trimitere, iar toate câmpurile invalide sunt raportate deodată.