PostgreSQL LISTEN/NOTIFY, minimum yapılandırmayla canlı panolar ve uyarılar sağlayabilir. Nerede işe yaradığını, sınırlamalarını ve ne zaman bir broker eklemeniz gerektiğini öğrenin.

Bir ürünün arayüzündeki “canlı güncellemeler” genellikle kullanıcı yenilemeye gerek kalmadan ekranda bir değişiklik olmasını sağlar. Bir gösterge panelindeki sayı artar, gelen kutusunda kırmızı bir rozet belirir, bir yönetici yeni bir siparişi görür ya da “Derleme tamamlandı” veya “Ödeme başarısız” diyen bir toast görünür. Önemli olan zamanlama: anlık gibi hissedilir, gerçekte bir veya iki saniye olsa bile.
Birçok ekip polling ile başlar: tarayıcı sunucuya her birkaç saniyede bir “yeni bir şey var mı?” diye sorar. Polling işe yarar, ama iki yaygın dezavantajı vardır.
İlk olarak, gecikmeli hissedilir çünkü kullanıcılar değişiklikleri yalnızca bir sonraki poll'da görür.
İkincisi, maliyetli olabilir çünkü hiçbir şey değişmediğinde bile sürekli kontroller yaparsınız. Bunu binlerce kullanıcı ile çarparsanız gürültüye dönüşür.
PostgreSQL LISTEN/NOTIFY daha basit bir vaka için vardır: “bir şey değiştiğinde haber ver.” Sürekli sormak yerine uygulamanız bekleyebilir ve veritabanı küçük bir sinyal gönderdiğinde tepki verebilir.
Bu, bir dürtü yeterli olan UI'lar için iyi bir eşleşmedir. Örneğin:
Takas basitlik ve garantiler arasındadır. LISTEN/NOTIFY Postgres içinde olduğu için eklemesi kolaydır, ama tam bir mesajlaşma sistemi değildir. Bildirim bir ipucudur, kalıcı bir kayıt değildir. Bir dinleyici bağlantısı kesilmişse sinyali kaçırabilir.
Pratik bir kullanım: NOTIFY uygulamanızı uyandırsın, sonra uygulamanız tabloları okuyup doğruyu alsın.
PostgreSQL LISTEN/NOTIFY'yi veritabanınıza yerleştirilmiş basit bir zil gibi düşünün. Uygulamanız zilin çalmasını bekleyebilir, sistemin başka bir parçası bir şey değiştiğinde çalabilir.
Bir bildirim iki parçadan oluşur: bir kanal adı ve isteğe bağlı bir yük. Kanal, bir başlık etiketi gibidir (örneğin orders_changed). Yük, eklediğiniz kısa bir metin mesajıdır (örneğin bir sipariş id'si). PostgreSQL hiç bir yapı zorunlu kılmaz, bu yüzden ekipler genellikle küçük JSON dizeleri gönderir.
Bildirim uygulama kodundan tetiklenebilir (API sunucunuz NOTIFY çalıştırır) veya veritabanının kendisinden bir tetikleyici ile (insert/update/delete sonrası NOTIFY çalıştıran bir trigger).
Alıcı tarafta, uygulama sunucunuz bir veritabanı bağlantısı açar ve LISTEN channel_name çalıştırır. Bu bağlantı açık kalır. Bir NOTIFY channel_name, 'payload' olduğunda, PostgreSQL o kanalı dinleyen tüm bağlantılara bir mesaj iletir. Uygulamanız sonra tepki verir (cache'i yenileme, değişen satırı alma, tarayıcıya WebSocket olayı itme vb.).
NOTIFY bir sinyal olarak anlaşılmalı, teslimat servisi olarak değil:
Bu şekilde kullanıldığında PostgreSQL LISTEN/NOTIFY ekstra altyapı eklemeden canlı UI güncellemelerini sağlayabilir.
LISTEN/NOTIFY, UI'nızın yalnızca bir şeyin değiştiğine dair bir dürtüye ihtiyaç duyduğu durumlarda parıldar, tam bir olay akışı yerine. "Bu widget'ı yenile" veya "yeni bir öğe var" gibi düşünün, "her tıklamayı sıralı olarak işle" değil.
Veritabanı zaten gerçeğin kaynağıysa ve UI'nın onunla senkron kalmasını istiyorsanız en iyi çalıştığı yer burasıdır. Yaygın bir desen: satırı yaz, küçük bir bildirim gönder (ID dahil), UI (veya bir API) en son durumu tekrar getsin.
LISTEN/NOTIFY genellikle şu durumlarda yeterlidir:
Somut bir örnek: dahili bir destek panosunda “açık talepler” ve “yeni notlar” rozeti gösterilir. Bir ajan not eklediğinde backend Postgres'e yazıp ticket_changed ile ticket ID'sini NOTIFY eder. Tarayıcı bunu WebSocket üzerinden alır ve yalnızca o bilet kartını yeniden getirir. Ekstra altyapı yok, UI yine canlı hisseder.
LISTEN/NOTIFY başta harika hissedebilir, ama sert sınırları vardır. Bu sınırlar, bildirimleri bir mesaj sistemi gibi ele aldığınızda ortaya çıkar.
En büyük boşluk dayanıklılıktır. NOTIFY bir kuyruk işi değildir. Kimse dinlemiyorsa mesaj kaybolur. Bir dinleyici bağlıyken bile çökme, deploy, ağ sorunu veya veritabanı yeniden başlatma bağlantıyı koparabilir. Kaçırılan bildirimleri otomatik olarak geri almazsınız.
Bağlantı kopmaları kullanıcıya yönelik özellikler için özellikle can sıkıcıdır. Bir gösterge panelini düşünün: tarayıcı sekmesi uykuya girer, WebSocket yeniden bağlanır ve UI “takılı” görünür çünkü birkaç olayı kaçırmıştır. Bunun etrafında çözümler geliştirebilirsiniz, ama çözüm artık sadece "LISTEN/NOTIFY" olmaz: durumu tekrar sorgulayarak yeniden inşa edersiniz ve NOTIFY sadece yenileme için bir ipucu olur.
Fan-out başka yaygın bir sorundur. Bir olay yüzlerce veya binlerce dinleyiciyi uyandırabilir (birçok app server, birçok kullanıcı). orders gibi tek bir gürültülü kanal kullanırsanız, her dinleyici uyanır hatta çoğu sadece görmezden gelir. Bu, CPU patlamalarına ve bağlantı baskısına neden olabilir.
Yük boyutu ve sıklık son tuzaklardır. NOTIFY yükleri küçüktür ve yüksek frekanslı olaylar istemcilerin işleyebileceğinden daha hızlı birikebilir.
Şunlara dikkat edin:
Bu noktada NOTIFY'ı bir "dürtü" olarak tutun ve güvenilirliği bir tabloya veya uygun bir mesaj aracısına taşıyın.
LISTEN/NOTIFY ile güvenilir bir desen, NOTIFY'ı dürtü, veri kaynağını tablo olarak ele almaktır. Veritabanı satırı gerçektir; bildirim uygulamanıza ne zaman bakacağını söyler.
Yazmayı bir işlem içinde yapın ve yalnızca veri değişikliği commit edildikten sonra bildirimi gönderin. Çok erken notify yaparsanız istemciler uyanır ve veriyi bulamayabilir.
Yaygın bir kurulum, INSERT/UPDATE tetikleyip küçük bir mesaj gönderen bir trigger'dır.
NOTIFY dashboard_updates, '{"type":"order_changed","order_id":123}'::text;
Kanal adlandırma, insanların sisteme nasıl düşündüğüne uyduğunda en iyi çalışır. Örnekler: dashboard_updates, user_notifications veya kiracı bazlı tenant_42_updates.
Yükü küçük tutun. Kimlikleri ve bir tür koyun, tam kayıtları değil. Faydalı bir varsayılan biçim:
type (ne oldu)id (ne değişti)tenant_id veya user_idBu, bant genişliğini düşük tutar ve hassas verilerin bildirim günlüklerine sızmasını önler.
Bağlantılar kopar. Buna hazırlıklı olun.
Bağlandığınızda gereken tüm kanallar için LISTEN çalıştırın. Bağlantı koptuğunda kısa bir backoff ile yeniden bağlanın. Yeniden bağlandıktan sonra (abonelikler taşınmaz) tekrar LISTEN yapın. Yeniden bağlandıktan sonra kaçırılmış olayları kapatmak için “son değişiklikleri” kısaca yeniden getirin.
Çoğu canlı UI güncellemesi için yeniden getirme en güvenli hamledir: istemci {type, id} alır, sonra en güncel durum için sunucuya sorar.
İncremental patchleme daha hızlı olabilir fakat yanlış olması daha kolaydır (sırasız olaylar, kısmi hatalar). Orta yol olarak: küçük dilimleri yeniden getirin (bir sipariş satırı, bir bilet kartı, bir rozet sayısı) ve ağır toplu sorguları kısa bir zamanlayıcı ile tutun.
Bir yönetici panosundan aynı sayıları izleyen pek çok kullanıcıya geçtiğinizde, iyi alışkanlıklar zekice SQL'den daha önemlidir. LISTEN/NOTIFY hâlâ iyi çalışabilir, ama olayların veritabanından tarayıcılara nasıl aktığını şekillendirmeniz gerekir.
Yaygın bir temel: her uygulama örneği bir uzun ömürlü bağlantı açar ve LISTEN yapar, sonra bağlı istemcilere güncellemeleri iter. "Her örnek için bir dinleyici" kurulumunun küçük sayıda sunucunuz varsa ve ara sıra yeniden bağlanmaları tolere edebiliyorsanız basit ve sıklıkla yeterlidir.
Eğer çok sayıda uygulama örneğiniz (veya serverless worker'ınız) varsa, paylaşılan bir dinleyici servisi daha kolay olabilir. Bir küçük süreç bir kez dinler, sonra güncellemeleri yığına fırlatır. Ayrıca toplama, metrik ve backpressure eklemek için tek bir nokta sağlar.
Tarayıcılar için genellikle WebSocket (çift yönlü, etkileşimli UI'lar için harika) veya Server-Sent Events (tek yönlü, panolar için daha basit) ile itersiniz. Her iki durumda da “her şeyi yenile” göndermekten kaçının. "Sipariş 123 değişti" gibi kompakt sinyaller gönderin ki UI yalnızca ihtiyacı olanı tekrar getirsin.
UI'nin çalkalanmasını önlemek için birkaç koruma ekleyin:
Kanal tasarımı da önemlidir. Tek bir küresel kanal yerine tenant, ekip veya özelliğe göre bölümlendirin ki istemciler sadece ilgili olayları alsın. Örnek: notify:tenant_42:billing ve notify:tenant_42:ops.
LISTEN/NOTIFY basit hissediyor; bu yüzden ekipler hızlıca yayınlar ve sonra üretimde şaşırır. Çoğu problem, onu garanti veren bir mesaj kuyruğu gibi kullanmaktan gelir.
Uygulamanız yeniden bağlanırsa (deploy, ağ arızası, DB failover), bağlı olmadığınız sırada gönderilen herhangi bir NOTIFY kaybolur. Çözüm: bildirimi bir sinyal olarak kullanın, sonra veritabanını tekrar kontrol edin.
Pratik desen: gerçek olayı bir tabloda saklayın (id ve created_at ile), sonra yeniden bağlandığınızda son gördüğünüz id'den daha yenileri için sorgulayın.
LISTEN/NOTIFY yükleri büyük JSON blob'lar için uygun değildir. Büyük yükler ekstra işlem, daha fazla ayrıştırma ve limitlere takılma riskini artırır.
Yükleri "order:123" gibi küçük ipuçları için kullanın. Uygulama sonra en güncel durumu veritabanından okur.
Yaygın bir hata, UI'yı bildirim yüküne dayanarak tasarlamaktır, sanki o gerçek kaynakmış gibi. Bu, şema değişikliklerini ve istemci sürümlerini zorlaştırır.
Temiz bir ayrım tutun: bir şey değiştiğini bildir, sonra normal bir sorgu ile güncel veriyi al.
Her satır değişiminde NOTIFY yapan tetikleyiciler sisteminizi boğabilir, özellikle yoğun tablolar için.
Sadece anlamlı geçişlerde notify yapın (örneğin durum değişimleri). Gürültülü güncellemeler varsa, değişiklikleri batch'leyin (örneğin bir işlem veya zaman penceresinde tek notify) veya bu güncellemeleri notify yolundan çıkarın.
Veritabanı bildirim gönderebilse bile UI hâlâ boğulabilir. Her olayda yeniden render eden bir pano donabilir.
İstemci tarafında güncellemeleri debounce edin, patlamaları tek bir yenilemeye sıkıştırın ve “her delta'yı uygula” yerine “geçersiz kıl ve yeniden getir” yaklaşımını tercih edin. Örneğin: bir bildirim zili anında güncellenebilir, ama açılır liste her birkaç saniyede en fazla bir kez yenilensin.
LISTEN/NOTIFY, uygulamanın taze veriyi getirmesi için küçük bir “bir şey değişti” sinyali istediğinizde harikadır. Tam bir mesajlaşma sistemi değildir.
Önce bu soruları yanıtlayın:
Pratik bir kural: NOTIFY'ı bir dürtü (go re-read the row) olarak kullanabiliyorsanız güvenli bölgedesiniz.
Örnek: bir yönetici panosu yeni siparişleri gösterir. Bir bildirim kaçırılırsa bir sonraki poll veya sayfa yenileme doğru sayıyı gösterir. Bu iyi bir uyumdur. Ancak "bu kartı tahsil et" veya "paketi gönder" gibi kritik ve geri alınamaz işler gönderiyorsanız, birini kaçırmak gerçek bir olaya yol açar.
Küçük bir satış uygulaması hayal edin: bir pano bugünün gelirini, toplam siparişleri ve "son siparişler" listesini gösterir. Aynı zamanda, her satış elemanı kendi siparişleri ödendiğinde veya gönderildiğinde hızlı bir bildirim almalıdır.
Basit yaklaşım Postgres'i gerçeğin kaynağı olarak kullanmak ve LISTEN/NOTIFY'ı sadece bir dürtü olarak kullanmaktır.
Bir sipariş oluşturulduğunda veya durumu değiştiğinde backend aynı istekte iki şey yapar: satırı yazar (veya günceller) ve sonra küçük bir NOTIFY gönderir (genellikle sadece sipariş ID'si ve olay türü). UI NOTIFY yüküne tam veri için güvenmez.
Pratik akış şöyle görünür:
orders_events kanalına {\"type\":\"status_changed\",\"order_id\":123} ile NOTIFY gönderin.Bu, NOTIFY'ı hafif tutar ve pahalı sorguları sınırlar.
Trafik arttığında çatlaklar görünür: olay patlamaları tek bir dinleyiciyi bunaltabilir, yeniden bağlanmada bildirimler kaçabilir ve garantili teslimat ile yeniden oynatma ihtiyacı doğar. Bu genelde daha güvenilir bir katman (outbox tablosu + işçi, sonra gerekirse broker) ekleme zamanıdır; Postgres yine gerçeğin kaynağı olmaya devam eder.
LISTEN/NOTIFY hızlı bir "bir şey değişti" sinyali için iyidir. Tam bir mesajlaşma sistemi olmak için tasarlanmamıştır. Olaylara güvenir hale geldiğinizde broker ekleme zamanı gelmiştir.
Aşağıdakilerden herhangi biri ortaya çıkarsa bir broker size sorunları çözer:
LISTEN/NOTIFY mesajları sonra için saklamaz. It bir itme sinyalidir, kalıcı bir log değil. Bu, pano widget'ını yenilemek için mükemmel ama "faturalandırmayı tetikle" veya "paketi gönder" gibi kritik iş akışları için risklidir.
Bir broker size gerçek bir mesaj akışı modeli sağlar: kuyruklar (yapılacak işler), topic'ler (birçok alıcıya yayın), retention (mesajları dakikalar ya da günler boyunca tutma) ve acknowledgments (tüketici işlediğini onaylar). Bu, "veritabanı değişti"yi "bu yüzden olması gereken her şey"den ayırmanıza izin verir.
En karmaşık aracı seçmek zorunda değilsiniz. İnsanların değerlendirdiği yaygın seçenekler Redis (pub/sub veya streams), NATS, RabbitMQ ve Kafka'dır. Doğru seçim, basit iş kuyruklarına mı, birçok servise fan-out'a mı yoksa geçmişin yeniden oynatılabilmesine mi ihtiyacınız olduğuna bağlıdır.
Büyük bir yeniden yazmaya gerek kalmadan geçiş yapabilirsiniz. Pratik desen: NOTIFY'ı uyanma sinyali olarak tutarken broker'ı teslim kaynağı yapın.
İlk olarak olay satırını aynı işlem içinde bir tabloya yazın, sonra bir işçi bu olayı broker'a yayınlasın. Geçiş sırasında NOTIFY UI katmanına "yeni olayları kontrol et" demeye devam edebilir, arka plan işçileri ise broker'dan retry ve audit ile tüketir.
Böylece panolar hızlı kalır ve kritik iş akışları en iyi çaba bildirimlerine bağlı kalmaz.
Bir ekran seçin (bir pano kartı, bir rozet sayısı, bir “yeni bildirim” toast'ı) ve uçtan uca bağlayın. LISTEN/NOTIFY ile dar kapsamlı tutulduğunda ve gerçek trafikte ölçtüğünüzde faydalı bir sonuç hızlıca alabilirsiniz.
En basit güvenli desenle başlayın: satırı yazın, commit edin, sonra küçük bir sinyal yayınlayın. UI sinyale tepki verip en güncel durumu (veya ihtiyacı olan dilimi) tekrar getirsin. Bu, yükleri küçük tutar ve mesajlar sırayla gelmediğinde ortaya çıkan ince hatalardan kaçınır.
Erken gözlemlenebilirlik ekleyin. Şık araçlara gerek yok ama sistem gürültülü hale geldiğinde cevap almanız şarttır:
Anlaşmaları sıkıcı ve yazılı tutun. Kanal adları, olay adları ve yük şekli (sadece bir ID olsa bile) konusunda karar verin. Repoda kısa bir "olay kataloğu" sürüm sürüm sürüntüyü engeller.
Hızlı inşa etmek istiyorsanız ve yığını basit tutmak istiyorsanız, Koder.ai (koder.ai) gibi bir platform ilk sürümü React UI, Go backend ve PostgreSQL ile çıkarmanıza yardımcı olabilir; gereksinimler netleştikçe yineleyebilirsiniz.
LISTEN/NOTIFY yalnızca bir şeyin değiştiğine dair hızlı bir işaret gerektiğinde kullanın; örneğin bir rozet sayısını veya pano karosunu yenilemek gibi. Bildirimi veri yerine bir dürtü olarak görün ve gerçek veriyi tablolardan tekrar alın.
Sorgulama belirli aralıklarla değişiklikleri kontrol eder; bu yüzden kullanıcılar genellikle güncellemeleri gecikmeli görür ve sunucu boşta birçok istek yapmak zorunda kalır. LISTEN/NOTIFY değişiklik olduğunda küçük bir sinyal gönderir; genelde daha hızlı hissedilir ve gereksiz istekleri azaltır.
Hayır — en iyisi elinden geleni yapma düzeyindedir. Bir NOTIFY gönderilirken dinleyici bağlantısı kopmuşsa sinyal kaçabilir çünkü bildirimler daha sonra yeniden oynatılmak üzere saklanmaz.
Küçük tutun ve bunu bir ipucu olarak kullanın. Pratik bir varsayılan küçük JSON: type ve id içerir; ardından uygulamanız Postgres'ten mevcut durumu sorgular.
Yazmayı commit ettikten sonra bildirim göndermek yaygın bir desendir. Çok erken notify yaparsanız, istemci uyandığında yeni satırı bulamayabilir.
Uygulama kodundan notify göndermek genellikle anlaşılması ve test edilmesi daha kolaydır çünkü açıktır. Birden çok yazarın aynı tabloyu değiştirdiği durumlarda tutarlı davranış için tetikleyiciler yararlıdır.
Yeniden bağlanmaları normal davranış olarak planlayın. Yeniden bağlandığınızda ihtiyaç duyduğunuz tüm kanallar için LISTEN'i tekrar çalıştırın ve çevrimdışı kaldığınız sırada kaçırmış olabileceklerinizi telafi etmek için kısa bir yeniden getirme yapın.
Her tarayıcının doğrudan Postgres'e bağlanmasını sağlamayın. Tipik bir kurulum: her backend örneği uzun ömürlü bir bağlantı açar ve LISTEN yapar, ardından tarayıcılara WebSocket veya SSE ile iletir; UI gerektiğini tekrar getirir.
Sadece ilgili tüketicilerin uyanması için daha dar kanallar kullanın ve gürültülü patlamaları toplu işleyin. İstemci tarafında birkaç yüz milisaniyelik debounce ve duplicate coalesce ile UI ve backend'in aşırı yüklenmesini önleyin.
Dayanıklılık, tekrar deneme, tüketici grupları, sıralama garantileri veya denetim/yeniden oynatma ihtiyacı ortaya çıktığında geçiş yapın. Bir olayı kaçırmanın gerçek bir olaya yol açacağı durumlarda (faturalama, gönderim gibi) outbox tablosu ve işçi veya özel bir broker kullanın.