فی الحال ٹیسٹنگ جاری ہے: مکمل ہونے پر GitHub کوڈ کھول دیا جائے گا۔

Ticketing Java / Kotlin لائبریری

GitHub Maven Central

ایک ہی TicketBroker تین کالنگ اسٹائل ایک ساتھ فراہم کرتا ہے — Kotlin coroutines کے لیے acquire، Java async کے لیے acquireAsync (CompletableFuture)، اور Java blocking کے لیے acquireBlocking۔ آپ کوئی بھی استعمال کریں، یہ ایک ہی broker اور ایک ہی کنکشنز ہیں۔

ریپوزیٹری

xml
kts

مثال

بنیادی مثال

Application startup پر ایک broker بنا کر share کریں۔ wait=0 queue کے بغیر ایک immediate attempt ہے، زیادہ سے زیادہ 255 سیکنڈ؛ lease 1–250 سیکنڈ۔ آخری minimum-work budget لازم اور 0 ہو سکتا ہے۔ Sub-second اوپر round ہوتے ہیں؛ out-of-range یا normalized lease سے بڑا budget send سے پہلے reject، 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.
}

Automatic close/drop bounded best-effort release ہے۔ Result اہم ہو تو explicit release API استعمال کریں۔ Token کو اسی DB transaction میں protected write fence کرنا لازم ہے۔

جاننے کے قابل رویّہ

  • ایک request byte بھی send ہوا ہو سکتا ہے تو final response کھونے کا نتیجہ Indeterminate ہے۔ اسی owner سے A auto-resend نہیں؛ caller critical section میں نہیں جاتا۔
  • Send سے پہلے cancel unsent؛ possible-send کے بعد session بند۔ ساتھ grant token parse ہو تو bounded compensating exact-token release۔
  • M، ہر E، malformed/oversized/unknown response session-fatal ہیں۔ Unresolved possible-send acquire Indeterminate۔
  • B یقینی capacity rejection ہے اور فوراً واپس۔ Internal retry نہیں؛ caller application backoff کے بعد نئے owner سے نیا acquire کر سکتا ہے۔
  • Explicit/compensating release exact token کو call/enqueue سے مطلق 5 سیکنڈ تک retry کرتا ہے۔ R success، N absent/not current؛ final response نہ ہو تو error، assumed success نہیں۔
  • Positive conservative remaining time اور کافی work budget پر ہی Ticket ملتا ہے۔ 250 سیکنڈ سے زیادہ work send سے پہلے unsupported۔
  • Token DB fencing لازم: اسی transaction میں token <= stored_high_water reject، high-water update اور business write، پھر commit/rollback اور release۔

حفاظتی اختیارات (ٹوکن · TLS)

تمام اختیارات اختیاری ہیں۔ token کو سرور کے client_tokens سے میل کھانا چاہیے، اور TLS کے چار موڈز ہیں: بند / سسٹم ٹرسٹ اسٹور / ایک مخصوص CA / تصدیق چھوڑنا (صرف ٹیسٹ کے لیے)۔

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

Java میں، static factories TlsMode.systemRoots() / TlsMode.ca("ca.crt") / TlsMode.insecureSkipVerify() استعمال کریں۔

سرور کی جانب سے ٹوکن، TLS، اور کلسٹر کنفیگریشن آپ Ticketing سرور تعیناتی صفحے پر بنا سکتے ہیں۔

Spring ورچوئل تھریڈز

اگر Spring MVC ورچوئل تھریڈز پر چل رہا ہو تو Java اور Kotlin دونوں میں *Blocking کالز استعمال کریں۔ نان-سسپینڈ کنٹرولر acquire کو نہیں بلا سکتا، اس لیے Kotlin میں بھی acquireBlocking ہی عام راستہ ہے۔ یہ کوروٹینز سے نہیں گزرتیں اور صرف جواب پر park ہوتی ہیں، چنانچہ کیریئر تھریڈ آزاد رہتا ہے۔

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 {
            // کریٹیکل سیکشن
        }
        return "ok"
    }
}

close() (‏try-with-resources / use) کے پیچھے ہونے والی بیک گراؤنڈ ریلیز بطورِ ڈیفالٹ ورچوئل تھریڈ ایگزیکیوٹر پر چلتی ہے، اس لیے یہ کبھی مقررہ سائز کے پول کے پیچھے قطار میں نہیں لگتی۔ Spring کا ایگزیکیوٹر استعمال کرنے کے لیے اپنا ایگزیکیوٹر پاس کریں۔

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

WebFlux یا کوروٹین کنٹرولرز کے ساتھ suspend کالز ہی استعمال کرتے رہیں۔