Saat ini dalam pengujian: kode GitHub akan dibuka setelah selesai.

Ticketing Java / Kotlin Library

GitHub Maven Central

Satu TicketBroker menyediakan tiga gaya pemanggilan sekaligus — coroutine Kotlin memakai acquire, Java async memakai acquireAsync (CompletableFuture), dan Java blocking memakai acquireBlocking. Apa pun yang Anda pakai, ini broker dan koneksi yang sama.

Repositori

xml
kts

Contoh

Contoh Dasar

Buat satu broker saat aplikasi mulai dan gunakan bersama. wait=0 adalah satu percobaan langsung tanpa queue, maksimum 255 detik; lease 1–250 detik. Minimum-work budget terakhir wajib dan boleh nol. Pecahan detik dibulatkan ke atas; nilai di luar rentang atau budget di atas lease ternormalisasi ditolak sebelum kirim, tidak pernah di-clamp.

Kotlin (coroutines):

kotlin
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):

java
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.
}

Close/drop otomatis adalah bounded best-effort release. Gunakan explicit release API bila hasil penting. Token wajib melakukan fencing pada DB write terlindungi di transaction yang sama.

Perilaku yang Perlu Diketahui

  • Jika satu request byte mungkin terkirim, hilangnya respons final menghasilkan Indeterminate. A tidak otomatis dikirim ulang dengan owner yang sama; caller tidak masuk critical section.
  • Cancel sebelum send adalah unsent; setelah possible-send menutup session. Jika grant token diparse bersamaan, dilakukan bounded compensating exact-token release.
  • M, semua E, dan response malformed/oversized/unknown adalah session-fatal. Acquire possible-send yang belum pasti menjadi Indeterminate.
  • B adalah capacity rejection pasti dan langsung dikembalikan. Tanpa retry internal; caller dapat memulai acquire baru dengan owner baru setelah application backoff.
  • Explicit/compensating release mencoba exact token hanya selama 5 detik absolut sejak call/enqueue. R sukses, N sudah hilang/bukan current; tanpa respons final adalah error, bukan diasumsikan sukses.
  • Ticket hanya diberikan dengan sisa waktu konservatif positif yang cukup untuk work budget. Work di atas 250 detik unsupported sebelum kirim.
  • DB fencing dengan token wajib: dalam transaction yang sama tolak token <= stored_high_water, perbarui high-water dan lakukan business write sebelum commit/rollback dan release.

Opsi Keamanan (Token · TLS)

Semua opsi bersifat opsional. token harus sesuai dengan client_tokens milik server, dan TLS punya empat mode: mati / trust store sistem / CA yang ditentukan / lewati verifikasi (khusus test).

kotlin
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()

Di Java, gunakan static factory TlsMode.systemRoots() / TlsMode.ca("ca.crt") / TlsMode.insecureSkipVerify().

Konfigurasi token, TLS, dan cluster di sisi server bisa Anda buat di halaman Deployment Server Ticketing.

Virtual Thread Spring

Jika Spring MVC berjalan di atas virtual thread, gunakan pemanggilan *Blocking — baik di Java maupun Kotlin. Controller non-suspend tidak bisa memanggil acquire, jadi acquireBlocking juga merupakan jalur normal di Kotlin. Pemanggilan ini tidak melewati coroutine dan hanya park pada balasan, sehingga carrier thread tetap bebas.

kotlin
@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 {
            // bagian kritis
        }
        return "ok"
    }
}

Pelepasan latar belakang dari close() (try-with-resources / use) secara bawaan berjalan di executor virtual thread, sehingga tidak pernah mengantre di belakang pool berukuran tetap. Berikan executor Anda sendiri untuk memakai milik Spring.

kotlin
TicketBroker.builder()
    .addrs("127.0.0.1:5225")
    .executor(applicationTaskExecutor)
    .connect()

Dengan WebFlux atau controller coroutine, tetap gunakan pemanggilan suspend.