Kotlin și Java
O singură bibliotecă pentru ambele limbaje: un API suspend pentru Kotlin și sendBlocking, sendAsync și builderi pentru Java, pe java.net.http.HttpClient. Singurele dependențe sunt biblioteca standard Kotlin și corutinele.
- Pachet
-
app.honk-me:sdkÎn curând - Cod sursă
- github.com/honk-me/honk-kotlin · Licență MIT
- Cerințe
- JDK 17 sau mai nou.
Publicarea pe Maven Central așteaptă namespace-ul Sonatype. Până atunci, compilează biblioteca din repository (./gradlew publishToMavenLocal) sau folosește cURL.
Instalare
Totul este în pachetul app.honkme.
// build.gradle.kts
dependencies { implementation("app.honk-me:sdk:0.1.0") } <!-- pom.xml -->
<dependency>
<groupId>app.honk-me</groupId>
<artifactId>sdk</artifactId>
<version>0.1.0</version>
</dependency> 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
Creează un singur Honk pentru fiecare aplicație și închide-l la oprire.
import app.honkme.Honk
val honk = Honk.fromEnvironment() // HONK_URL, HONK_KEY (+ HONK_SOURCE, HONK_ENVIRONMENT, HONK_CHANNEL)
honk.beep("Backup finished", "nightly pg_dump took 42 s") // suspend import app.honkme.Honk;
import app.honkme.Message;
Honk honk = Honk.fromEnvironment();
honk.sendBlocking(Message.beep("Backup finished", "nightly pg_dump took 42 s").build()); Rețetă: cererea unui client, cu Spring Boot sau Ktor
Biblioteca nu depinde de Spring; acesta este cod obișnuit într-un serviciu Spring. Trimite după commit-ul tranzacției, ca clientul să nu aștepte niciodată după rețea.
@Configuration
class HonkConfig {
@Bean(destroyMethod = "close")
Honk honk(@Value("${honk.url}") String url, @Value("${honk.key}") String key) {
return Honk.builder().url(url).key(key).build(); // one client, keep-alive
}
}
@Service
class CustomerRequestNotifier {
private static final Logger log = LoggerFactory.getLogger(CustomerRequestNotifier.class);
private final Honk honk;
CustomerRequestNotifier(Honk honk) { this.honk = honk; }
// After the request is saved: never block the customer's request on the network.
@TransactionalEventListener
void on(CustomerRequestCreated event) {
CustomerRequest r = event.request();
Message message = Message.light("New request: " + r.subject(), r.name() + " (" + r.company() + ") asked: " + r.body())
.priority("high") // push right away
.category(Category.CUSTOMERS)
.channel("requests")
.groupKey("requests/" + r.id()) // one group per request
.url("https://shop.example.com/admin/requests/" + r.id()) // https only
.meta("request_id", String.valueOf(r.id()))
.build();
honk.sendAsync(message, "request-" + r.id()) // same request, same key
.exceptionally(e -> { log.warn("honk: {}", e.getMessage()); return null; });
}
} scope.launch {
honk.light("New request: ${r.subject}", "${r.name} (${r.company}) asked: ${r.body.take(2000)}") {
priority(Priority.HIGH)
category(Category.CUSTOMERS)
groupKey("requests/${r.id}")
url("https://shop.example.com/admin/requests/${r.id}")
idempotencyKey("request-${r.id}")
}
} Scala Honk și incidentele
În Java, Message.longHonk(…) ține locul lui long, care este cuvânt rezervat.
honk.loud("Disk 91%", "/var on app-01") { groupKey("disk/app-01/var") }
honk.problem("db/backup", "Backup failed", "pg_dump exited with 1") // a long honk by default
honk.recovery("db/backup", "Backup OK", "pg_dump finished in 41 s") // a beep by default
honk.send(Message("Imported 1 204 rows", severity = Severity.BEEP, channel = "imports")) Erori
Toate excepțiile sunt unchecked și extind HonkException, cu isRetryable și cheia de idempotență cu care să reîncerci.
try {
honk.sendBlocking(Message.longHonk("Payment failed", "Stripe declined order 1042").groupKey("payments/stripe").build());
} catch (HonkValidationException e) {
log.error("bug: {}", e.getFields());
} catch (HonkException e) {
if (e.isRetryable()) queue.retryLater(e.getIdempotencyKey(), e.getRetryAfter());
else throw e;
} 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 șiduplicate: 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și5xx, cu backoff exponențial și jitter complet, niciodată mai devreme decâtRetry-Afterde la server. Celelalte răspunsuri4xxnu 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ă.