2026-04-10 23:20:41 -04:00
---
layout: default
title: "Pub/Sub Altyapı sı "
parent: "Turkish (Beta)"
---
2026-04-11 01:08:44 +00:00
# Pub/Sub Altyapı sı
2026-04-10 23:20:41 -04:00
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
2026-04-11 01:08:44 +00:00
## Genel Bakı ş
Bu belge, TrustGraph kod tabanı ile pub/sub altyapı sı arası ndaki tüm bağlantı ları listeler. Şu anda sistem, Apache Pulsar'ı kullanmak üzere sabit kodlanmı ştı r. Bu analiz, yapı landı rı labilir bir pub/sub soyutlaması na yönelik gelecekteki yeniden düzenlemeleri bilgilendirmek için tüm entegrasyon noktaları nı belirler.
## Mevcut Durum: Pulsar Entegrasyon Noktaları
### 1. Doğrudan Pulsar İstemci Kullanı mı
**Konum:** `trustgraph-flow/trustgraph/gateway/service.py`
API ağ geçidi, doğrudan Pulsar istemcisini içe aktarı r ve örnekler:
**Satı r 20:** `import pulsar`
**Satı rlar 54-61:** `pulsar.Client()` 'ı n doğrudan örneklenmesi, isteğe bağlı `pulsar.AuthenticationToken()` ile birlikte
**Satı rlar 33-35:** Ortam değişkenlerinden varsayı lan Pulsar ana bilgisayarı yapı landı rması
**Satı rlar 178-192:** `--pulsar-host` , `--pulsar-api-key` ve `--pulsar-listener` için CLI argümanları
**Satı rlar 78, 124:** `pulsar_client` 'ı `ConfigReceiver` ve `DispatcherManager` 'ye geçirir
Bu, bir soyutlama katmanı dı şı nda bir Pulsar istemcisinin doğrudan örneklenmesini yapan tek konumdur.
### 2. Temel İşlemci Çerçevesi
**Konum:** `trustgraph-base/trustgraph/base/async_processor.py`
Tüm işlemciler için temel sı nı f, Pulsar bağlantı sı sağlar:
**Satı r 9:** `import _pulsar` (istisna işleme için)
**Satı r 18:** `from . pubsub import PulsarClient`
**Satı r 38:** `pulsar_client_object = PulsarClient(**params)` oluşturur
**Satı rlar 104-108:** `pulsar_host` ve `pulsar_client` 'i ortaya koyan özellikler
**Satı r 250:** Statik yöntem `add_args()` , CLI argümanları için `PulsarClient.add_args(parser)` 'i çağı rı r
**Satı rlar 223-225:** `_pulsar.Interrupted` için istisna işleme
Tüm işlemciler `AsyncProcessor` 'dan türetildiği için, bu merkezi bir entegrasyon noktası dı r.
### 3. Tüketici Soyutlaması
**Konum:** `trustgraph-base/trustgraph/base/consumer.py`
Kuyruklardan mesajlar tüketir ve işleyici fonksiyonları nı çağı rı r:
**Pulsar içe aktarmaları :**
**Satı r 12:** `from pulsar.schema import JsonSchema`
**Satı r 13:** `import pulsar`
**Satı r 14:** `import _pulsar`
**Pulsar'a özgü kullanı m:**
**Satı rlar 100, 102:** `pulsar.InitialPosition.Earliest` / `pulsar.InitialPosition.Latest`
**Satı r 108:** `JsonSchema(self.schema)` sarmalayı cı sı
**Satı r 110:** `pulsar.ConsumerType.Shared`
**Satı rlar 104-111:** Pulsar'a özgü parametrelerle `self.client.subscribe()`
**Satı rlar 143, 150, 65:** `consumer.unsubscribe()` ve `consumer.close()` yöntemleri
**Satı r 162:** `_pulsar.Timeout` istisnası
**Satı rlar 182, 205, 232:** `consumer.acknowledge()` / `consumer.negative_acknowledge()`
**Belge dosyası :** `trustgraph-base/trustgraph/base/consumer_spec.py`
**Satı r 22:** `processor.pulsar_client` 'a referans
### 4. Yayı ncı Soyutlaması
**Konum:** `trustgraph-base/trustgraph/base/producer.py`
Kuyruklara mesaj gönderir:
**Pulsar içe aktarmaları :**
**Satı r 2:** `from pulsar.schema import JsonSchema`
**Pulsar'a özgü kullanı m:**
**Satı r 49:** `JsonSchema(self.schema)` sarmalayı cı sı
**Satı rlar 47-51:** Pulsar'a özgü parametrelerle (konu, şema, chunking_enabled) `self.client.create_producer()`
**Satı rlar 31, 76:** `producer.close()` yöntemi
**Satı rlar 64-65:** Mesaj ve özelliklerle `producer.send()`
**Belge dosyası :** `trustgraph-base/trustgraph/base/producer_spec.py`
**Satı r 18:** `processor.pulsar_client` 'a referans
### 5. Yayı ncı Soyutlaması
**Konum:** `trustgraph-base/trustgraph/base/publisher.py`
Kuyruklu tamponlama ile asenkron mesaj yayı nlama:
**Pulsar içe aktarmaları :**
**Satı r 2:** `from pulsar.schema import JsonSchema`
**Satı r 6:** `import pulsar`
**Pulsar'a özgü kullanı m:**
**Satı r 52:** `JsonSchema(self.schema)` sarmalayı cı sı
**Satı rlar 50-54:** Pulsar'a özgü parametrelerle `self.client.create_producer()`
**Satı rlar 101, 103:** Mesaj ve isteğe bağlı özelliklerle `producer.send()`
**Satı rlar 106-107:** `producer.flush()` ve `producer.close()` yöntemleri
### 6. Abonelik Soyutlaması
**Konum:** `trustgraph-base/trustgraph/base/subscriber.py`
Kuyruklardan çoklu alı cı ya mesaj dağı tı mı sağlar:
**Pulsar importları :**
**6. Satı r:** `from pulsar.schema import JsonSchema`
**8. Satı r:** `import _pulsar`
**Pulsar'a özgü kullanı m:**
**55. Satı r:** `JsonSchema(self.schema)` wrapper
**57. Satı r:** `self.client.subscribe(**subscribe_args)`
**101, 136, 160, 167-172. Satı rlar:** Pulsar istisnaları : `_pulsar.Timeout` , `_pulsar.InvalidConfiguration` , `_pulsar.AlreadyClosed`
**159, 166, 170. Satı rlar:** Tüketici metotları : `negative_acknowledge()` , `unsubscribe()` , `close()`
**247, 251. Satı rlar:** Mesaj onayı : `acknowledge()` , `negative_acknowledge()`
**Spec dosyası :** `trustgraph-base/trustgraph/base/subscriber_spec.py`
**19. Satı r:** `processor.pulsar_client` 'a referans
### 7. Şema Sistemi (Heart of Darkness)
**Konum:** `trustgraph-base/trustgraph/schema/`
Sistemdeki her mesaj şeması , Pulsar'ı n şema çerçevesi kullanı larak tanı mlanı r.
**Temel öğeler:** `schema/core/primitives.py`
**2. Satı r:** `from pulsar.schema import Record, String, Boolean, Array, Integer`
Tüm şemalar, Pulsar'ı n `Record` temel sı nı fı ndan türetilir.
Tüm alan türleri Pulsar türleridir: `String()` , `Integer()` , `Boolean()` , `Array()` , `Map()` , `Double()`
**Örnek şemalar:**
`schema/services/llm.py` (2. Satı r): `from pulsar.schema import Record, String, Array, Double, Integer, Boolean`
`schema/services/config.py` (2. Satı r): `from pulsar.schema import Record, Bytes, String, Boolean, Array, Map, Integer`
**Konu adlandı rması :** `schema/core/topic.py`
**2-3. Satı rlar:** Konu formatı : `{kind}://{tenant}/{namespace}/{topic}`
Bu URI yapı sı Pulsar'a özgüdür (örneğin, `persistent://tg/flow/config` )
**Etki:**
Kod tabanı ndaki tüm istek/yanı t mesaj tanı mları , Pulsar şemaları nı kullanı r.
Bu, aşağı daki hizmetler için geçerlidir: yapı landı rma, akı ş, LLM, istem, sorgu, depolama, aracı , koleksiyon, tanı , kütüphane, arama, NLP sorgusu, nesne sorgusu, alma, yapı landı rı lmı ş sorgu.
Şema tanı mları , tüm işlemciler ve hizmetler genelinde kapsamlı bir şekilde içe aktarı lı r ve kullanı lı r.
## Özet
### Kategoriye Göre Pulsar Bağı mlı lı kları
1. **İstem oluşturma:**
Doğrudan: `gateway/service.py`
Soyutlanmı ş: `async_processor.py` → `pubsub.py` (PulsarClient)
2. **Mesaj taşı ma:**
Tüketici: `consumer.py` , `consumer_spec.py`
Üretici: `producer.py` , `producer_spec.py`
Yayı ncı : `publisher.py`
Abonelik: `subscriber.py` , `subscriber_spec.py`
3. **Şema sistemi:**
Temel türler: `schema/core/primitives.py`
Tüm hizmet şemaları : `schema/services/*.py`
Konu adlandı rması : `schema/core/topic.py`
4. **Gereken Pulsar'a özgü kavramlar:**
Konuya dayalı mesajlaşma
Şema sistemi (Kayı t, alan türleri)
Paylaşı mlı abonelikler
Mesaj onayı (olumlu/olumsuz)
Tüketici konumlandı rması (en erken/en son)
Mesaj özellikleri
Başlangı ç konumları ve tüketici türleri
Parçalama desteği
Kalı cı ve kalı cı olmayan konular
### Yeniden Düzenleme Zorlukları
İyi haber: Soyutlama katmanı (Tüketici, Üretici, Yayı ncı , Abonelik), çoğu Pulsar etkileşimini temiz bir şekilde kapsar.
Zorluklar:
1. **Şema sisteminin yaygı nlı ğı :** Her mesaj tanı mı `pulsar.schema.Record` ve Pulsar alan türlerini kullanı r.
2. **Pulsar'a özgü numaralandı rmalar:** `InitialPosition` , `ConsumerType`
3. **Pulsar istisnaları :** `_pulsar.Timeout` , `_pulsar.Interrupted` , `_pulsar.InvalidConfiguration` , `_pulsar.AlreadyClosed`
4. **Metot imzaları :** `acknowledge()` , `negative_acknowledge()` , `subscribe()` , `create_producer()` , vb.
5. **Konu URI formatı :** Pulsar'ı n `kind://tenant/namespace/topic` yapı sı
### Sonraki Adı mlar
Yayı n/abone altyapı sı nı yapı landı rı labilir hale getirmek için şunları yapmamı z gerekiyor:
1. İstem/şema sistemi için bir soyutlama arayüzü oluşturun.
2. Pulsar'a özgü numaralandı rmaları ve istisnaları soyutlayı n.
3. Şema sargı ları veya alternatif şema tanı mları oluşturun.
4. Arayüzü hem Pulsar hem de alternatif sistemler (Kafka, RabbitMQ, Redis Streams, vb.) için uygulayı n.
5. `pubsub.py` 'ı yapı landı rı labilir hale getirin ve çoklu arka uçları destekleyin.
6. Mevcut dağı tı mlar için bir geçiş yolu sağlayı n.
## Yaklaşı m Taslağı 1: Şema Çeviri Katmanı yla Adaptör Kalı bı
### Temel Bilgi
**Şema sistemi**, en derin entegrasyon noktası dı r - her şey ondan kaynaklanı r. Önce bunu çözmemiz gerekiyor, aksi takdirde tüm kodu yeniden yazmamı z gerekecek.
### Strateji: Minimum Bozulma ile Adaptörler
**1. Pulsar şemaları nı , dahili gösterim olarak koruyun**
Tüm şema tanı mları nı yeniden yazmayı n
Şemalar, dahili olarak `pulsar.schema.Record` olarak kalı r
Adaptörleri, kendi kodumuz ile yayı n/abonelik arka ucu arası ndaki sı nı rdaki çevirileri yapmak için kullanı n
**2. Bir yayı n/abonelik soyutlama katmanı oluşturun:**
```
┌─────────────────────────────────────┐
│ Existing Code (unchanged) │
│ - Uses Pulsar schemas internally │
│ - Consumer/Producer/Publisher │
└──────────────┬──────────────────────┘
│
┌──────────────┴──────────────────────┐
│ PubSubFactory (configurable) │
│ - Creates backend-specific client │
└──────────────┬──────────────────────┘
│
┌──────┴──────┐
│ │
┌───────▼─────┐ ┌────▼─────────┐
│ PulsarAdapter│ │ KafkaAdapter │ etc...
│ (passthrough)│ │ (translates) │
└──────────────┘ └──────────────┘
```
**3. Soyut arayüzleri tanı mlayı n:**
`PubSubClient` - istemci bağlantı sı
`PubSubProducer` - mesaj gönderme
`PubSubConsumer` - mesaj alma
`SchemaAdapter` - Pulsar şemaları nı JSON'a veya arka uç özel formatları na dönüştürme/dönüştürme
**4. Uygulama detayları :**
**Pulsar adaptörü için:** Neredeyse doğrudan geçiş, minimum çeviri
**Diğer arka uçlar için** (Kafka, RabbitMQ, vb.):
Pulsar Kayı t nesnelerini JSON/byte'a serileştirin
Aşağı daki kavramları eşleyin:
`InitialPosition.Earliest/Latest` → Kafka'nı n auto.offset.reset'i
`acknowledge()` → Kafka'nı n commit'i
`negative_acknowledge()` → Yeniden kuyruklama veya DLQ deseni
Konu URI'leri → Arka uç özel konu adları
### Analiz
**Artı ları :**
✅ Mevcut hizmetlerde minimum kod değişikliği
✅ Şemalar olduğu gibi kalı r (büyük bir yeniden yazı m olmaz)
✅ Aşamalı geçiş yolu
✅ Pulsar kullanı cı ları hiçbir fark görmez
✅ Yeni arka uçlar adaptörler aracı lı ğı yla eklenir
**Eksileri:**
⚠️ Hala Pulsar bağı mlı lı ğı taşı r (şema tanı mları için)
⚠️ Kavramları çevirirken bazı uyumsuzluklar olabilir
### Alternatif Düşünce
Bir **TrustGraph şema sistemi** oluşturun; bu sistem, pub/sub'dan bağı msı zdı r (dataclass'lar veya Pydantic kullanarak). Ardı ndan, bu sistemden Pulsar/Kafka/vb. şemaları nı oluşturun. Bu, her şema dosyası nı n yeniden yazı lması nı gerektirir ve potansiyel olarak uyumsuzluklara neden olabilir.
### Taslak 1 için Öneri
**Adaptör yaklaşı mı yla** başlayı n çünkü:
1. Pratik bir yaklaşı mdı r - mevcut kodla çalı şı r
2. Minimum riskle kavramı kanı tlar
3. Gerekirse daha sonra yerel bir şema sistemine dönüştürülebilir
4. Yapı landı rma odaklı dı r: tek bir ortam değişkeni arka uçları değiştirir
## Yaklaşı m Taslağı 2: Dataclass'larla Arka Uçtan Bağı msı z Şema Sistemi
### Temel Kavram
Python **dataclass'ları ** tarafsı z şema tanı mı formatı olarak kullanı n. Her pub/sub arka ucu, dataclass'lar için kendi serileştirme/deserileştirme işlemlerini sağlar; bu, Pulsar şemaları nı n kod tabanı nda kalma ihtiyacı nı ortadan kaldı rı r.
### Fabrika Seviyesinde Şema Çok Biçimliliği
Pulsar şemaları nı çevirmek yerine, **her arka uç, standart Python dataclass'ları yla çalı şan kendi şema işleme yöntemini sağlar** .
### Yayı ncı Akı şı
```python
# 1. Get the configured backend from factory
pubsub = get_pubsub() # Returns PulsarBackend, MQTTBackend, etc.
# 2. Get schema class from the backend
# (Can be imported directly - backend-agnostic)
from trustgraph.schema.services.llm import TextCompletionRequest
# 3. Create a producer/publisher for a specific topic
producer = pubsub.create_producer(
topic="text-completion-requests",
schema=TextCompletionRequest # Tells backend what schema to use
)
# 4. Create message instances (same API regardless of backend)
request = TextCompletionRequest(
system="You are helpful",
prompt="Hello world",
streaming=False
)
# 5. Send the message
producer.send(request) # Backend serializes appropriately
```
### Tüketici Akı şı
```python
# 1. Get the configured backend
pubsub = get_pubsub()
# 2. Create a consumer
consumer = pubsub.subscribe(
topic="text-completion-requests",
schema=TextCompletionRequest # Tells backend how to deserialize
)
# 3. Receive and deserialize
msg = consumer.receive()
request = msg.value() # Returns TextCompletionRequest dataclass instance
# 4. Use the data (type-safe access)
print(request.system) # "You are helpful"
print(request.prompt) # "Hello world"
print(request.streaming) # False
```
### Sahne Arkası ndaki Olaylar
**Pulsar arka ucu için:**
`create_producer()` → JSON şeması veya dinamik olarak oluşturulmuş bir kayı tla Pulsar üreticisi oluşturur.
`send(request)` → veri sı nı fı nı JSON/Pulsar formatı na serileştirir ve Pulsar'a gönderir.
`receive()` → Pulsar mesajı nı alı r, veri sı nı fı na geri serileştirir.
**MQTT arka ucu için:**
`create_producer()` → MQTT aracı sı na bağlanı r, şema kaydı gerektirmez.
`send(request)` → veri sı nı fı nı JSON'a dönüştürür ve MQTT konusuna yayı nlar.
`receive()` → MQTT konusuna abone olur, JSON'ı veri sı nı fı na geri serileştirir.
**Kafka arka ucu için:**
`create_producer()` → Kafka üreticisini oluşturur, gerekirse Avro şeması nı kaydeder.
`send(request)` → veri sı nı fı nı Avro formatı na serileştirir ve Kafka'ya gönderir.
`receive()` → Kafka mesajı nı alı r, Avro'yu veri sı nı fı na geri serileştirir.
### Temel Tasarı m Noktaları
1. **Şema nesnesi oluşturma** : Veri sı nı fı örneği (`TextCompletionRequest(...)` ), arka uçtan bağı msı z olarak aynı dı r.
2. **Arka uç, kodlamayı yönetir** : Her arka uç, veri sı nı fı nı kablo formatı na nası l serileştireceğini bilir.
3. **Oluşturma sı rası nda şema tanı mı ** : Üretici/tüketici oluştururken, şema türünü belirtirsiniz.
4. **Tür güvenliği korunur** : Doğru bir `TextCompletionRequest` nesnesi alı rsı nı z, bir sözlük değil.
5. **Arka uç sı zı ntı sı yok** : Uygulama kodu, arka uçla ilgili özel kütüphaneleri asla içe aktarmaz.
### Örnek Dönüşüm
**Mevcut (Pulsar'a özel):**
```python
# schema/services/llm.py
from pulsar.schema import Record, String, Boolean, Integer
class TextCompletionRequest(Record):
system = String()
prompt = String()
streaming = Boolean()
```
**Yeni (Arka uçtan bağı msı z):**
```python
# schema/services/llm.py
from dataclasses import dataclass
@dataclass
class TextCompletionRequest:
system: str
prompt: str
streaming: bool = False
```
### Arka Uç Entegrasyonu
Her arka uç, veri sı nı fları nı n serileştirme/deserileştirme işlemlerini gerçekleştirir:
**Pulsar arka ucu:**
Veri sı nı fları ndan dinamik olarak `pulsar.schema.Record` sı nı fları oluşturun
Veya veri sı nı fları nı JSON'a serileştirin ve Pulsar'ı n JSON şeması nı kullanı n
Mevcut Pulsar kurulumları yla uyumluluğu korur
**MQTT/Redis arka ucu:**
Veri sı nı fı örneklerinin doğrudan JSON serileştirilmesi
`dataclasses.asdict()` / `from_dict()` kullanı n
Hafif, şema kayı t defterine gerek yok
**Kafka arka ucu:**
Veri sı nı fı tanı mları ndan Avro şemaları oluşturun
Confluent'ı n şema kayı t defterini kullanı n
Şema evrimi desteğiyle tür güvenli serileştirme
### Mimari
```
┌─────────────────────────────────────┐
│ Application Code │
│ - Uses dataclass schemas │
│ - Backend-agnostic │
└──────────────┬──────────────────────┘
│
┌──────────────┴──────────────────────┐
│ PubSubFactory (configurable) │
│ - get_pubsub() returns backend │
└──────────────┬──────────────────────┘
│
┌──────┴──────┐
│ │
┌───────▼─────────┐ ┌────▼──────────────┐
│ PulsarBackend │ │ MQTTBackend │
│ - JSON schema │ │ - JSON serialize │
│ - or dynamic │ │ - Simple queues │
│ Record gen │ │ │
└─────────────────┘ └───────────────────┘
```
### Uygulama Detayları
**1. Şema tanı mları :** Basit dataclass'lar ve tür ipuçları
`str` , `int` , `bool` , `float` temel veri tipleri için
`list[T]` diziler için
`dict[str, T]` haritalar için
Karmaşı k tipler için iç içe dataclass'lar
**2. Her arka uç şunları sağlar:**
Serileştirici: `dataclass → bytes/wire format`
Seri dı şa aktarı cı : `bytes/wire format → dataclass`
Şema kaydı (gerekirse, örneğin Pulsar/Kafka)
**3. Tüketici/Üretici soyutlaması :**
Zaten mevcut (consumer.py, producer.py)
Arka uç tarafı ndan sağlanan seri dı şa aktarmayı kullanmak için güncellenmeli
Doğrudan Pulsar içe aktarmaları nı kaldı rmalı
**4. Tür eşlemeleri:**
Pulsar `String()` → Python `str`
Pulsar `Integer()` → Python `int`
Pulsar `Boolean()` → Python `bool`
Pulsar `Array(T)` → Python `list[T]`
Pulsar `Map(K, V)` → Python `dict[K, V]`
Pulsar `Double()` → Python `float`
Pulsar `Bytes()` → Python `bytes`
### Geçiş Yolu
1. `trustgraph/schema/` içindeki tüm şemaları n **dataclass versiyonları nı oluşturun**
2. Arka uç tarafı ndan sağlanan seri dı şa aktarmayı kullanmak için **arka uç sı nı fları nı (Tüketici, Üretici, Yayı ncı , Abonelik) güncelleyin**
3. JSON şeması nı veya dinamik Kayı t oluşturmayı kullanarak **PulsarBackend'i uygulayı n**
4. **Mevcut dağı tı mlarla geriye dönük uyumluluğu sağlamak için Pulsar ile test edin**
5. Gerekirse **yeni arka uçlar ekleyin (MQTT, Kafka, Redis, vb.)**
6. Şema dosyaları ndan **Pulsar içe aktarmaları nı kaldı rı n**
### Avantajlar
✅ **Şema tanı mları nda herhangi bir yayı n/abonelik bağı mlı lı ğı yok**
✅ **Standart Python** - anlaşı lması , tür denetimi yapı lması ve belgelenmesi kolay
✅ **Modern araçlar** - mypy, IDE otomatik tamamlama, lint araçları yla çalı şı r
✅ **Arka uç odaklı ** - her arka uç yerel seri dı şa aktarmayı kullanı r
✅ **Çeviri ek yükü yok** - doğrudan seri dı şa aktarma, adaptörler yok
✅ **Tür güvenliği** - uygun türlere sahip gerçek nesneler
✅ **Kolay doğrulama** - gerekirse Pydantic kullanı labilir
### Zorluklar & Çözümler
**Zorluk:** Pulsar'ı n `Record` 'ı çalı şma zamanı alan doğrulaması na sahiptir
**Çözüm:** Gerekirse doğrulama için Pydantic dataclass'ları nı kullanı n veya `__post_init__` ile Python 3.10+ dataclass özelliklerini kullanı n
**Zorluk:** Bazı Pulsar'a özgü özellikler (örneğin `Bytes` türü)
**Çözüm:** Bu türü dataclass'ta `bytes` türüne eşleyin, arka uç uygun şekilde kodlamayı işler
**Zorluk:** Konu adlandı rması (`persistent://tenant/namespace/topic` )
**Çözüm:** Şema tanı mları nda konu adları nı soyutlayı n, arka uç uygun formata dönüştürür
**Zorluk:** Şema evrimi ve sürüm oluşturma
**Çözüm:** Her arka uç, yeteneklerine göre bunu işler (Pulsar şema sürümleri, Kafka şema kaydı , vb.)
**Zorluk:** İç içe karmaşı k türler
**Çözüm:** İç içe dataclass'ları kullanı n, arka uçlar yinelemeli olarak seri dı şa aktarı r/serileştirir
### Tasarı m Kararları
1. **Basit dataclass'lar mı yoksa Pydantic mi?**
✅ **Karar: Basit Python dataclass'ları kullanı n**
Daha basit, ek bağı mlı lı k yok
Uygulamada doğrulama gerekli değil
Anlaşı lması ve bakı mı daha kolay
2. **Şema evrimi:**
✅ **Karar: Herhangi bir sürüm oluşturma mekanizması na gerek yok**
Şemalar kararlı ve uzun ömürlü
Güncellemeler genellikle yeni alanlar ekler (geriye dönük uyumlu)
Arka uçlar, yeteneklerine göre şema evrimini işler
3. **Geriye dönük uyumluluk:**
✅ **Karar: Ana sürüm değişikliği, geriye dönük uyumluluk gerekli değil**
Bu, bir kopma değişikliği olacak ve geçiş talimatları sağlanacak
Temiz bir kopma, daha iyi bir tasarı m sağlar
Mevcut dağı tı mlar için bir geçiş kı lavuzu sağlanacaktı r
4. **İç içe türler ve karmaşı k yapı lar:**
✅ **Karar: İç içe dataclass'ları doğal olarak kullanı n**
Python dataclass'ları iç içe geçmeyi mükemmel şekilde işler
Diziler için `list[T]` , haritalar için `dict[K, V]`
Arka uçlar yinelemeli olarak seri dı şa aktarı r/serileştirir
Örnek:
```python
@dataclass
class Value:
value: str
is_uri: bool
@dataclass
class Triple:
s: Value # Nested dataclass
p: Value
o: Value
@dataclass
class GraphQuery:
triples: list[Triple] # Array of nested dataclasses
metadata: dict[str, str]
```
5. **Varsayı lan değerler ve isteğe bağlı alanlar:**
✅ **Karar: Gerekli, varsayı lan ve isteğe bağlı alanları n birleşimi**
Gerekli alanlar: Herhangi bir varsayı lan değer yok
Varsayı lan değerlere sahip alanlar: Her zaman mevcut, anlamlı varsayı lan değerlere sahip
Tamamen isteğe bağlı alanlar: `T | None = None` , `None` olduğunda serileştirmeden çı karı lı r
Örnek:
```python
@dataclass
class TextCompletionRequest:
system: str # Required, no default
prompt: str # Required, no default
streaming: bool = False # Optional with default value
metadata: dict | None = None # Truly optional, can be absent
```
**Önemli serileştirme kuralları :**
`metadata = None` olduğunda:
```json
{
"system": "...",
"prompt": "...",
"streaming": false
// metadata field NOT PRESENT
}
```
`metadata = {}` (açı kça boş) olduğunda:
```json
{
"system": "...",
"prompt": "...",
"streaming": false,
"metadata": {} // Field PRESENT but empty
}
```
**Temel ayrı m:**
`None` → JSON'da bulunmayan alan (serileştirilmiyor)
Boş değer (`{}` , `[]` , `""` ) → alan, boş bir değerle mevcut
Bu, anlamsal olarak önemlidir: "sağlanmadı " ile "açı kça boş"
Serileştirme arka uçları , `None` alanları nı atlamalı , bunları `null` olarak kodlamamalı dı r.
## Yaklaşı m Taslağı 3: Uygulama Detayları
### Genel Kuyruk Adlandı rma Formatı
Arka uçlara özgü kuyruk adları nı , arka uçları n uygun şekilde eşleyebileceği genel bir formata dönüştürün.
**Format:** `{qos}/{tenant}/{namespace}/{queue-name}`
Nerede:
`qos` : Hizmet kalitesi seviyesi
`q0` = en iyi çaba (ateşle ve unut, onay yok)
`q1` = en az bir kez (onay gerektirir)
`q2` = tam olarak bir kez (iki aşamalı onay)
`tenant` : Çok kiracı lı lı k için mantı ksal gruplandı rma
`namespace` : Kiracı içindeki alt gruplandı rma
`queue-name` : Gerçek kuyruk/konu adı
**Örnekler:**
```
q1/tg/flow/text-completion-requests
q2/tg/config/config-push
q0/tg/metrics/stats
```
### Arka Uç Konu Eşlemesi
Her arka uç, genel formatı kendi yerel formatı na eşler:
**Pulsar Arka Ucu:**
```python
def map_topic(self, generic_topic: str) -> str:
# Parse: q1/tg/flow/text-completion-requests
qos, tenant, namespace, queue = generic_topic.split('/', 3)
# Map QoS to persistence
persistence = 'persistent' if qos in ['q1', 'q2'] else 'non-persistent'
# Return Pulsar URI: persistent://tg/flow/text-completion-requests
return f"{persistence}://{tenant}/{namespace}/{queue}"
```
**MQTT Altyapı sı :**
```python
def map_topic(self, generic_topic: str) -> tuple[str, int]:
# Parse: q1/tg/flow/text-completion-requests
qos, tenant, namespace, queue = generic_topic.split('/', 3)
# Map QoS level
qos_level = {'q0': 0, 'q1': 1, 'q2': 2}[qos]
# Build MQTT topic including tenant/namespace for proper namespacing
mqtt_topic = f"{tenant}/{namespace}/{queue}"
return mqtt_topic, qos_level
```
### Güncellenmiş Konu Yardı mcı Fonksiyonu
```python
# schema/core/topic.py
def topic(queue_name, qos='q1', tenant='tg', namespace='flow'):
"""
Create a generic topic identifier that can be mapped by backends.
Args:
queue_name: The queue/topic name
qos: Quality of service
- 'q0' = best-effort (no ack)
- 'q1' = at-least-once (ack required)
- 'q2' = exactly-once (two-phase ack)
tenant: Tenant identifier for multi-tenancy
namespace: Namespace within tenant
Returns:
Generic topic string: qos/tenant/namespace/queue_name
Examples:
topic('my-queue') # q1/tg/flow/my-queue
topic('config', qos='q2', namespace='config') # q2/tg/config/config
"""
return f"{qos}/{tenant}/{namespace}/{queue_name}"
```
### Yapı landı rma ve Başlatma
**Komut Satı rı Argümanları + Ortam Değişkenleri:**
```python
# In base/async_processor.py - add_args() method
@staticmethod
def add_args(parser):
# Pub/sub backend selection
parser.add_argument(
'--pubsub-backend',
default=os.getenv('PUBSUB_BACKEND', 'pulsar'),
choices=['pulsar', 'mqtt'],
help='Pub/sub backend (default: pulsar, env: PUBSUB_BACKEND)'
)
# Pulsar-specific configuration
parser.add_argument(
'--pulsar-host',
default=os.getenv('PULSAR_HOST', 'pulsar://localhost:6650'),
help='Pulsar host (default: pulsar://localhost:6650, env: PULSAR_HOST)'
)
parser.add_argument(
'--pulsar-api-key',
default=os.getenv('PULSAR_API_KEY', None),
help='Pulsar API key (env: PULSAR_API_KEY)'
)
parser.add_argument(
'--pulsar-listener',
default=os.getenv('PULSAR_LISTENER', None),
help='Pulsar listener name (env: PULSAR_LISTENER)'
)
# MQTT-specific configuration
parser.add_argument(
'--mqtt-host',
default=os.getenv('MQTT_HOST', 'localhost'),
help='MQTT broker host (default: localhost, env: MQTT_HOST)'
)
parser.add_argument(
'--mqtt-port',
type=int,
default=int(os.getenv('MQTT_PORT', '1883')),
help='MQTT broker port (default: 1883, env: MQTT_PORT)'
)
parser.add_argument(
'--mqtt-username',
default=os.getenv('MQTT_USERNAME', None),
help='MQTT username (env: MQTT_USERNAME)'
)
parser.add_argument(
'--mqtt-password',
default=os.getenv('MQTT_PASSWORD', None),
help='MQTT password (env: MQTT_PASSWORD)'
)
```
**Fabrika Fonksiyonu:**
```python
# In base/pubsub.py or base/pubsub_factory.py
def get_pubsub(**config) -> PubSubBackend:
"""
Create and return a pub/sub backend based on configuration.
Args:
config: Configuration dict from command-line args
Must include 'pubsub_backend' key
Returns:
Backend instance (PulsarBackend, MQTTBackend, etc.)
"""
backend_type = config.get('pubsub_backend', 'pulsar')
if backend_type == 'pulsar':
return PulsarBackend(
host=config.get('pulsar_host'),
api_key=config.get('pulsar_api_key'),
listener=config.get('pulsar_listener'),
)
elif backend_type == 'mqtt':
return MQTTBackend(
host=config.get('mqtt_host'),
port=config.get('mqtt_port'),
username=config.get('mqtt_username'),
password=config.get('mqtt_password'),
)
else:
raise ValueError(f"Unknown pub/sub backend: {backend_type}")
```
**AsyncProcessor'da Kullanı m:**
```python
# In async_processor.py
class AsyncProcessor:
def __init__ (self, **params):
self.id = params.get("id")
# Create backend from config (replaces PulsarClient)
self.pubsub = get_pubsub(**params)
# Rest of initialization...
```
### Arka Uç Arayüzü
```python
class PubSubBackend(Protocol):
"""Protocol defining the interface all pub/sub backends must implement."""
def create_producer(self, topic: str, schema: type, **options) -> BackendProducer:
"""
Create a producer for a topic.
Args:
topic: Generic topic format (qos/tenant/namespace/queue)
schema: Dataclass type for messages
options: Backend-specific options (e.g., chunking_enabled)
Returns:
Backend-specific producer instance
"""
...
def create_consumer(
self,
topic: str,
subscription: str,
schema: type,
initial_position: str = 'latest',
consumer_type: str = 'shared',
**options
) -> BackendConsumer:
"""
Create a consumer for a topic.
Args:
topic: Generic topic format (qos/tenant/namespace/queue)
subscription: Subscription/consumer group name
schema: Dataclass type for messages
initial_position: 'earliest' or 'latest' (MQTT may ignore)
consumer_type: 'shared', 'exclusive', 'failover' (MQTT may ignore)
options: Backend-specific options
Returns:
Backend-specific consumer instance
"""
...
def close(self) -> None:
"""Close the backend connection."""
...
```
```python
class BackendProducer(Protocol):
"""Protocol for backend-specific producer."""
def send(self, message: Any, properties: dict = {}) -> None:
"""Send a message (dataclass instance) with optional properties."""
...
def flush(self) -> None:
"""Flush any buffered messages."""
...
def close(self) -> None:
"""Close the producer."""
...
```
```python
class BackendConsumer(Protocol):
"""Protocol for backend-specific consumer."""
def receive(self, timeout_millis: int = 2000) -> Message:
"""
Receive a message from the topic.
Raises:
TimeoutError: If no message received within timeout
"""
...
def acknowledge(self, message: Message) -> None:
"""Acknowledge successful processing of a message."""
...
def negative_acknowledge(self, message: Message) -> None:
"""Negative acknowledge - triggers redelivery."""
...
def unsubscribe(self) -> None:
"""Unsubscribe from the topic."""
...
def close(self) -> None:
"""Close the consumer."""
...
```
```python
class Message(Protocol):
"""Protocol for a received message."""
def value(self) -> Any:
"""Get the deserialized message (dataclass instance)."""
...
def properties(self) -> dict:
"""Get message properties/metadata."""
...
```
### Mevcut Sı nı fları n Yeniden Düzenlenmesi
Mevcut `Consumer` , `Producer` , `Publisher` , `Subscriber` sı nı fları büyük ölçüde aynı kalacaktı r:
**Mevcut sorumluluklar (saklanacak):**
Asenkron iş parçacı ğı modeli ve görev grupları
Yeniden bağlantı mantı ğı ve tekrar deneme işleme
Ölçüm toplama
Hı z sı nı rlama
Eşzamanlı lı k yönetimi
**Gerekli değişiklikler:**
Doğrudan Pulsar içe aktarmaları nı kaldı rı n (`pulsar.schema` , `pulsar.InitialPosition` , vb.)
`BackendProducer` /`BackendConsumer` 'i Pulsar istemcisi yerine kullanı n
Gerçek yayı n/abonelik işlemlerini arka uç örneklerine devredin
Genel kavramları arka uç çağrı ları na eşleyin
**Örnek yeniden düzenleme:**
```python
# OLD - consumer.py
class Consumer:
def __init__ (self, client, topic, subscriber, schema, ...):
self.client = client # Direct Pulsar client
# ...
async def consumer_run(self):
# Uses pulsar.InitialPosition, pulsar.ConsumerType
self.consumer = self.client.subscribe(
topic=self.topic,
schema=JsonSchema(self.schema),
initial_position=pulsar.InitialPosition.Earliest,
consumer_type=pulsar.ConsumerType.Shared,
)
# NEW - consumer.py
class Consumer:
def __init__ (self, backend_consumer, schema, ...):
self.backend_consumer = backend_consumer # Backend-specific consumer
self.schema = schema
# ...
async def consumer_run(self):
# Backend consumer already created with right settings
# Just use it directly
while self.running:
msg = await asyncio.to_thread(
self.backend_consumer.receive,
timeout_millis=2000
)
await self.handle_message(msg)
```
### Arka Uç Özel Davranı şlar
**Pulsar Arka Uç:**
`q0` 'ı `non-persistent://` 'e, `q1` /`q2` 'ü `persistent://` 'e eşler.
Tüm tüketici türlerini (paylaşı mlı , özel, yedekli) destekler.
Başlangı ç konumunu (en erken/en son) destekler.
Yerel mesaj onayı .
Şema kayı t defteri desteği.
**MQTT Arka Uç:**
`q0` /`q1` /`q2` 'yi MQTT QoS seviyeleri 0/1/2'ye eşler.
Adlandı rma için konu yoluna kiracı /isim alanı ekler.
Abonelik adları ndan otomatik olarak istemci kimlikleri oluşturur.
Başlangı ç konumunu yoksayar (temel MQTT'de mesaj geçmişi yoktur).
Tüketici türünü yoksayar (MQTT, tüketici grupları yerine istemci kimlikleri kullanı r).
Basit yayı n/abone modeli.
### Tasarı m Kararları Özeti
1. ✅ **Genel kuyruk adlandı rması ** : `qos/tenant/namespace/queue-name` formatı
2. ✅ **Kuyruk kimliğindeki QoS** : Kuyruk tanı mı tarafı ndan belirlenir, yapı landı rma ile değil.
3. ✅ **Yeniden bağlanma** : Tüketici/Üretici sı nı fları tarafı ndan işlenir, arka uçlar tarafı ndan değil.
4. ✅ **MQTT konuları ** : Doğru adlandı rma için kiracı /isim alanı içerir.
5. ✅ **Mesaj geçmişi** : MQTT, `initial_position` parametresini yoksayar (gelecek geliştirmeler).
6. ✅ **İstemci kimlikleri** : MQTT arka ucu, abonelik adı ndan otomatik olarak oluşturur.
### Gelecek Geliştirmeler
**MQTT mesaj geçmişi:**
İsteğe bağlı bir kalı cı lı k katmanı eklenebilir (örneğin, saklanan mesajlar, harici depolama).
`initial_position='earliest'` 'ı desteklemeyi mümkün kı lacaktı r.
Başlangı ç uygulaması nda gerekli değildir.