Bibliothèque Ticketing Java / Kotlin
GitHub Maven CentralUn seul TicketBroker propose trois styles d'appel ensemble — les coroutines Kotlin utilisent acquire, l'asynchrone Java utilise acquireAsync (CompletableFuture), et le mode bloquant Java utilise acquireBlocking. Quel que soit celui utilisé, c'est le même broker et les mêmes connexions.
Dépôt
Exemple
Exemple simple
Créez un broker au démarrage et partagez-le. wait=0 est une tentative immédiate sans file, au maximum 255 s ; lease vaut 1–250 s. Le minimum-work budget final est obligatoire et peut valoir zéro. Les fractions de seconde sont arrondies vers le haut et les valeurs hors plage ou un budget supérieur au bail normalisé sont rejetés avant envoi, jamais clampés.
Kotlin (coroutines):
val broker = TicketBroker.connect("127.0.0.1:5225")
broker.waitReady(Duration.ofSeconds(5))
val ticket = broker.acquire("key", Duration.ofSeconds(5), Duration.ofSeconds(30), Duration.ofSeconds(2))
val token = ticket.token
// In the same DB transaction: verify/update token high-water and perform the business write.
ticket.release()Java (blocking):
TicketBroker broker = TicketBroker.connect("127.0.0.1:5225");
broker.waitReadyBlocking(Duration.ofSeconds(5));
try (Ticket ticket = broker.acquireBlocking(
"key", Duration.ofSeconds(5), Duration.ofSeconds(30), Duration.ofSeconds(2))) {
long token = ticket.getToken();
// In the same DB transaction: verify/update token high-water and perform the business write.
}Le close/drop automatique est un release borné best-effort. Utilisez l'API de release explicite si le résultat compte. Le token doit protéger l'écriture DB dans la même transaction.
Bon à savoir (comportement)
- Dès qu'un byte a pu être envoyé, la perte de la réponse définitive produit Indeterminate. Aucun renvoi automatique de
Aavec le même owner ; le caller n'entre pas en section critique. - Cancel avant envoi est unsent ; après possible-send il ferme la session. Si un grant token a été parsé en parallèle, un release compensatoire exact-token borné est tenté.
M, tous lesEet les réponses malformed/oversized/unknown sont session-fatal. Un acquire possible-send non résolu devient Indeterminate.Best un refus certain de capacity, rendu immédiatement. Aucun retry interne ; le caller peut démarrer un nouvel acquire avec nouvel owner et backoff applicatif.- Les releases explicites/compensatoires ne retentent l'exact token que pendant 5 secondes absolues depuis call/enqueue.
Rréussit,Nsignifie absent ou non courant ; sans réponse finale, erreur, jamais succès supposé. - Ticket n'est rendu qu'avec un temps conservateur positif suffisant pour le work budget. Un travail de plus de 250 s est unsupported avant envoi.
- Le fencing DB par token est obligatoire : dans la même transaction, rejeter
token <= stored_high_water, mettre à jour high-water et effectuer le business write avant commit/rollback puis release.
Options de sécurité (Token · TLS)
Toutes les options sont facultatives. token doit correspondre au client_tokens du serveur, et TLS propose quatre modes : désactivé / magasin de confiance système / CA spécifiée / vérification ignorée (test uniquement).
val broker = TicketBroker.builder()
.addrs("10.0.0.1:5225", "10.0.0.2:5225", "10.0.0.3:5225")
.token("123")
.tls(TlsMode.SystemRoots)
// .tls(TlsMode.Ca("ca.crt"))
// .tls(TlsMode.InsecureSkipVerify)
.connect()En Java, utilisez les fabriques statiques TlsMode.systemRoots() / TlsMode.ca("ca.crt") / TlsMode.insecureSkipVerify().
Vous pouvez générer le jeton, le TLS et la configuration de cluster côté serveur sur la page Déploiement du serveur Ticketing.
Threads virtuels Spring
Si Spring MVC tourne sur des threads virtuels, utilisez les appels *Blocking, en Java comme en Kotlin. Un contrôleur non suspendu ne peut pas appeler acquire : en Kotlin aussi, acquireBlocking est donc la voie normale. Ils ne passent pas par les coroutines et ne se garent que sur la réponse, le thread porteur reste donc libre.
@RestController
class OrderController(private val broker: TicketBroker) {
@PostMapping("/orders/{id}")
fun place(@PathVariable id: String): String {
broker.acquireBlocking("order-$id", Duration.ofSeconds(5), Duration.ofSeconds(30)).use {
// section critique
}
return "ok"
}
}La libération en arrière-plan de close() (try-with-resources / use) s'exécute par défaut sur un exécuteur à threads virtuels : elle ne s'accumule jamais derrière un pool de taille fixe. Passez votre propre exécuteur pour utiliser celui de Spring.
TicketBroker.builder()
.addrs("127.0.0.1:5225")
.executor(applicationTaskExecutor)
.connect()Avec WebFlux ou des contrôleurs à coroutines, continuez d'utiliser les appels suspend.