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.