Her borsa hız limitlerini yayımlar ve her borsa bunları uygular. Binance, hız limitine takılan bir REST çağrısını HTTP 429 ve uymanız beklenen bir Retry-After başlığıyla yanıtlar, saniyede 5 mesajdan fazlasını gönderen bir WebSocket bağlantısını da kapatır. Birbirinden yalnızca birkaç gün arayla iki müşteri raporu geldi, her biri bu konunun bir yarısıyla ilgiliydi ve ikisi birlikte düzgün biçimde çözülmeyi hak eden üç sorunu ortaya çıkardı.
Üçü de artık düzeltildi. Bunlardan birinin Binance'ten çok daha fazlasını etkilediği ortaya çıktı.
Başarısız bir istek eskiden başlıklarını çöpe atıyordu
Hazır API istemcilerinden biri üzerinden yapılan bir istek HTTP hata durumuyla başarısız olduğunda, bileşen durum kodunu, durum metnini ve gövdeyi taşıyan bir istisna fırlatıyordu. Yanıt başlıkları ise yok olmuştu. Gizlenmiş değil, tamamen yok olmuş. İstisna hâlâ yığında yukarı doğru ilerlerken HTTP nesnesi yok ediliyordu ve başlıklar da onunla birlikte gidiyordu.
Bu da bileşenin üzerine kurallara uygun bir Binance geri çekilme mantığı inşa etmeyi imkânsız kılıyordu. Retry-After ne kadar bekleyeceğinizi tam olarak söyler, bunu göz ardı etmek ise 429'dan HTTP 418'e ve geçici bir IP yasağına kadar tırmanır. Binance'in döndürdüğü X-MBX-USED-WEIGHT-1M gibi hız limiti sayaçlarına da aynı şekilde erişilemiyordu, dolayısıyla bir uygulama duvara toslamadan önce kendi hızını ayarlayamıyordu.
Fırlatılan istisna artık EsgcHTTPAPIProtocolException ve yanıt başlıklarını da beraberinde taşıyor. Daha önce fırlatılan istisnadan türediği için mevcut işleyiciler onu yakalamayı sürdürüyor, yeni bilgiyi kullanmak istemediğiniz sürece hiçbir şeyi değiştirmeniz gerekmiyor.
try
vResponse := oBinance.GetAggregateTrades('BTCUSDT');
except
on E: EsgcHTTPAPIProtocolException do
begin
if E.ErrorCode = 429 then
Sleep(E.RetryAfterMs);
vWeight := E.GetHeader('X-MBX-USED-WEIGHT-1M');
// E.ResponseHeaders holds the complete list
end;
end;
RetryAfterMs gecikmeyi milisaniye cinsinden döndürür ve başlığın alabileceği her iki biçimi de anlar, yani düz saniye sayısını ve HTTP tarihini. Başlık yoksa -1 döndürür. Düzeltme yalnızca Get için değil, sekiz istek metodunun tamamı için geçerli. Post ve Query metotlarının zaten kabul ettiği ResponseHeaders parametresi de artık bir istek başarısız olduğunda dolduruluyor, yani tam da ona ihtiyaç duyduğunuz anda.
Bununla birlikte bilmekte fayda var: 2026.7.0 sürümünden beri HTTP istemcisi beklemeyi sizin yerinize yapabiliyor.
oBinance.RetryOptions.Enabled := True;
oBinance.RetryOptions.MaxRetries := 3;
// HonorRetryAfter is already True by default
On iki çerçeve yerine tek çerçeve
Binance WebSocket protokolü, tek bir SUBSCRIBE çerçevesinde akış listesi kabul eder. Bileşen bunu kullanmıyordu. Her Subscribe* yardımcı metodu, tam olarak tek bir akış taşıyan bir çerçeveyi anında yazıyordu, dolayısıyla iki kanal üzerinde altı sembolden oluşan sıradan bir izleme listesi birkaç milisaniye içinde on iki çerçeve gönderiyordu. Binance de belgelerinde yazdığı gibi bağlantıyı kapatıyordu.
Artık listenin tamamını tek çerçeve olarak gönderen toplu gönderim metotları var:
oBinance.SubscribeStreams(['btcusdt@aggTrade', 'btcusdt@depth',
'ethusdt@aggTrade', 'ethusdt@depth']);
Bir çerçeve, yüzlerce akışla bile 8 KB'lik istek sınırının çok altında kalır, bu yüzden pratikte bir izleme listesi her zaman tek çerçevedir. UnsubscribeStreams ise bunun aynadaki karşılığıdır.
Kimsenin etrafından dolaşamadığı kısım
En çok önem taşıyan sorun buydu ve raporların hiçbiri onu tam olarak yakalayamamıştı.
Her borsa API'si, yeniden bağlandıktan sonra geri yükleyebilmek için abone olduğunuz kanalları saklar. Bu tekrar, akış başına bir çerçeveyi arka arkaya, hiçbir hız ayarı olmadan, henüz birkaç milisaniyelik olan bir bağlantıya gönderiyordu. Gerçekçi büyüklükteki herhangi bir izleme listesi, yeni bağlantının anında kapatılmasına yol açıyordu. Ardından WatchDog yeniden bağlanıyor, aynı seriyi tekrar gönderiyor ve bağlantı yine kapatılıyordu. Tek bir geçici kopma, kalıcı bir yeniden bağlanma döngüsüne dönüşüyordu.
Bu seri bileşenin içinde üretildiği için bir uygulamanın bundan kaçınması mümkün değildi. Yardımcı metotlar yerine kendi çerçevelerinizi yazmak da işe yaramıyordu, çünkü tekrar sizin çağırdığınız bir şey değil.
Kütüphanenin geri kalanının denetlenmesi, aynı tekrar döngüsünün 17 borsa API'sine kopyalanmış olduğunu gösterdi: Binance, Bitfinex, Bitget, Bitmex, Bitstamp, Bybit, Cex, CexPlus, Coinbase, CryptoCom, Deribit, GateIO, Huobi, Kraken, Kucoin, MEXC ve OKX. Her biri kendi borsasının limitine karşı.
Artık WebSocket API istemcilerinde bir Throttle seçeneği var:
oBinance.Throttle.Enabled := True; // paces your own Subscribe calls
oBinance.Throttle.MaxMessages := 4; // default, leaves room for PING/PONG
oBinance.Throttle.IntervalMs := 1000; // default
Varsayılan değer bir açıklamayı hak ediyor, çünkü kasıtlı olarak asimetrik. Throttle.Enabled varsayılan olarak False, yani uygulamanızın yaptığı çağrıların zamanlaması siz istemediğiniz sürece değişmiyor. Ancak Throttle.PaceResubscribe varsayılan olarak True, yani yeniden bağlanma tekrarı hiçbir ayar yapmadan hız denetimine tabi.
Gerekçesi basit. Kendi abonelik döngünüzü siz denetlersiniz ve toplu hale getirebilirsiniz, dolayısıyla oradaki hız ayarı sizin kararınız. Tekrarı ise siz denetlemiyorsunuz, bu yüzden sizin adınıza hız ayarı yapılıyor. Böylece yeniden bağlanma döngüsü, hiçbir kod değişikliği olmadan mevcut her uygulama için düzeltilmiş oluyor. Binance'te tekrar aynı zamanda birleşik çerçeveler olarak gönderiliyor, yani on iki akışlık bir izleme listesi artık on iki çerçeve yerine tek çerçeve olarak tekrarlanıyor. Önceki davranışı istiyorsanız PaceResubscribe değerini False yapın.
Birden fazla borsa kullanıyorsanız bir ayrıntı: saniyede 4 mesajlık varsayılan bütçe, belgelenmiş limiti 5 olan Binance'e uygundur. OKX ise 3 olarak belgeliyor, bu yüzden OKX istemcisinin varsayılanı 3'tür. MaxMessages değerini yükseltmeden önce borsanızın limitini kontrol edin.
Yükseltme
Doğrudan yerine geçer. Yeni istisna daha önce fırlatılandan türüyor, toplu gönderim metotları birer ekleme ve Throttle, yeniden bağlanmaları bozan tekrar dışında her şey için varsayılan olarak kapalı. En son sürümü sgcWebSockets indirme sayfasından indirin.
Bunların ikisi de kaynak kodu okumaya, sorunu yeniden üretmeye ve tam olarak yazıya dökmeye vakit ayıran müşterilerden geldi. Üçüncü ve en kötü hata da böyle bulundu. Bileşenlerde açıklayamadığınız bir davranışla karşılaşırsanız bize bildirin.
Sorularınız, geri bildiriminiz ya da geçiş için yardıma mı ihtiyacınız var? Bize ulaşın, yanıtı kodu yazan kişilerden alacaksınız.
