trustgraph/docs/tech-specs/multi-tenant-support.he.md
Alex Jenkins 8954fa3ad7 Feat: TrustGraph i18n & Documentation Translation Updates (#781)
Native CLI i18n: The TrustGraph CLI has built-in translation support
that dynamically loads language strings. You can test and use
different languages by simply passing the --lang flag (e.g., --lang
es for Spanish, --lang ru for Russian) or by configuring your
environment's LANG variable.

Automated Docs Translations: This PR introduces autonomously
translated Markdown documentation into several target languages,
including Spanish, Swahili, Portuguese, Turkish, Hindi, Hebrew,
Arabic, Simplified Chinese, and Russian.
2026-04-14 12:08:32 +01:00

780 lines
33 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
layout: default
title: "מפרט טכני: תמיכה בריבוי דיירים"
parent: "Hebrew (Beta)"
---
# מפרט טכני: תמיכה בריבוי דיירים
> **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.
## סקירה כללית
אפשר ריבוי פריסות דיירים על ידי תיקון חוסר התאמות בשמות הפרמטרים שמונע התאמה אישית של תורים, והוספת פרמטריזציה של מרחבי מפתחות Cassandra.
## הקשר ארכיטקטוני
### פתרון תורים מבוסס זרימה
מערכת TrustGraph משתמשת בארכיטקטורה **מבוססת זרימה** לפתרון דינמי של תורים, התומכת באופן מובנה בריבוי דיירים:
**הגדרות זרימה** מאוחסנות ב-Cassandra ומציינות שמות תורים באמצעות הגדרות ממשק.
**שמות התורים משתמשים בתבניות** עם משתנים `{id}` שמוחלפים במזהי מופעי זרימה.
**השירותים פותרים באופן דינמי את התורים** על ידי חיפוש תצורות זרימה בזמן בקשה.
**לכל דייר יכולות להיות זרימות ייחודיות** עם שמות תורים שונים, המספקות בידוד.
דוגמה להגדרת ממשק זרימה:
```json
{
"interfaces": {
"triples-store": "persistent://tg/flow/triples-store:{id}",
"graph-embeddings-store": "persistent://tg/flow/graph-embeddings-store:{id}"
}
}
```
כאשר שוכר א מתחיל זרימה `tenant-a-prod` ושוכר ב מתחיל זרימה `tenant-b-prod`, הם באופן אוטומטי מקבלים תורים מבודדים:
`persistent://tg/flow/triples-store:tenant-a-prod`
`persistent://tg/flow/triples-store:tenant-b-prod`
**שירותים המעוצבים כראוי עבור ריבוי שוכרים:**
**ניהול ידע (ליבה)** - פותר באופן דינמי תורים מהגדרת הזרימה המועברת בבקשות
**שירותים הדורשים תיקונים:**
🔴 **שירות תצורה** - חוסר התאמה בשם הפרמטר מונע התאמה אישית של תורים
🔴 **שירות ספרית** - נושאים של ניהול אחסון מקודדים (נדון בהמשך)
🔴 **כל השירותים** - לא ניתן להתאים אישית את מרחב המפתחות של Cassandra
## הצהרת בעיה
### בעיה #1: חוסר התאמה בשם פרמטר ב-AsyncProcessor
**הגדרות CLI:** `--config-queue` (שם לא ברור)
**Argparse ממיר ל:** `config_queue` (במילון הפרמטרים)
**הקוד מחפש:** `config_push_queue`
**תוצאה:** הפרמטר מתעלם, ברירת מחדל ל-`persistent://tg/config/config`
**השפעה:** משפיע על כל 32+ שירותים היורשים מ-AsyncProcessor
**חוסם:** פריסות מרובות שוכרים לא יכולות להשתמש בתורי תצורה ספציפיים לשוכר
**פתרון:** לשנות את שם הפרמטר ב-CLI ל-`--config-push-queue` לצורך בהירות (שינוי שבירה מקובל מכיוון שהתכונה שבורה כרגע)
### בעיה #2: חוסר התאמה בשם פרמטר בשירות התצורה
**הגדרות CLI:** `--push-queue` (שם מעורפל)
**Argparse ממיר ל:** `push_queue` (במילון הפרמטרים)
**הקוד מחפש:** `config_push_queue`
**תוצאה:** הפרמטר מתעלם
**השפעה:** שירות התצורה לא יכול להשתמש בתור דחיפה מותאם אישית
**פתרון:** לשנות את שם הפרמטר ב-CLI ל-`--config-push-queue` לצורך עקביות ובהירות (שינוי שבירה מקובל)
### בעיה #3: מרחב מפתחות Cassandra מקודד
**נוכחי:** מרחב המפתחות מקודד כ-`"config"`, `"knowledge"`, `"librarian"` בשירותים שונים
**תוצאה:** לא ניתן להתאים אישית את מרחב המפתחות עבור פריסות מרובות שוכרים
**השפעה:** שירותי תצורה, ליבה וספריה
**חוסם:** מספר שוכרים לא יכולים להשתמש במרחבי מפתחות Cassandra נפרדים
### בעיה #4: ארכיטקטורת ניהול אוספים ✅ הושלם
**קודם:** אוספים שמורים במרחב המפתחות של Cassandra של הספריה באמצעות טבלת אוספים נפרדת
**קודם:** הספריה השתמשה ב-4 נושאים מקודדים לניהול אחסון לתאם יצירה/מחיקה של אוספים:
`vector_storage_management_topic`
`object_storage_management_topic`
`triples_storage_management_topic`
`storage_management_response_topic`
**בעיות (טופלו):**
נושאים מקודדים לא ניתן להתאים אישית עבור פריסות מרובות שוכרים
תיאום אסינכרוני מורכב בין הספריה לבין 4+ שירותי אחסון
טבלה נפרדת ותשתית ניהול
תורי בקשה/תגובה לא מתמידים עבור פעולות קריטיות
**פתרון מיושם:** העברנו אוספים לשירות האחסון של התצורה, השתמשנו בדחיפה של תצורה להפצה
**סטטוס:** כל בסיסי האחסון עברו לדפוס `CollectionConfigHandler`
## פתרון
מפרט זה מתייחס לבעיות #1, #2, #3 ו-#4.
### חלק 1: תיקון חוסר התאמה בשמות פרמטרים
#### שינוי 1: מחלקת בסיס AsyncProcessor - שינוי שם פרמטר CLI
**קובץ:** `trustgraph-base/trustgraph/base/async_processor.py`
**שורה:** 260-264
**נוכחי:**
```python
parser.add_argument(
'--config-queue',
default=default_config_queue,
help=f'Config push queue {default_config_queue}',
)
```
**קבוע:**
```python
parser.add_argument(
'--config-push-queue',
default=default_config_queue,
help=f'Config push queue (default: {default_config_queue})',
)
```
**הסבר:**
שם ברור וחד יותר
תואם לשם המשתנה הפנימי `config_push_queue`
שינוי משמעותי מקובל מכיוון שהפיצ'ר אינו פעיל כרגע
אין צורך בשינוי קוד בפונקציה params.get() - היא כבר מחפשת את השם הנכון
#### שינוי 2: שירות תצורה - שינוי שם פרמטר שורת הפקודה
**קובץ:** `trustgraph-flow/trustgraph/config/service/service.py`
**שורה:** 276-279
**נוכחי:**
```python
parser.add_argument(
'--push-queue',
default=default_config_push_queue,
help=f'Config push queue (default: {default_config_push_queue})'
)
```
**קבוע:**
```python
parser.add_argument(
'--config-push-queue',
default=default_config_push_queue,
help=f'Config push queue (default: {default_config_push_queue})'
)
```
**הסבר:**
שמות ברורים יותר - "config-push-queue" מפורט יותר מ-"push-queue" בלבד.
תואם לשם המשתנה הפנימי `config_push_queue`.
עקבי עם הפרמטר `--config-push-queue` של AsyncProcessor.
שינוי שעלול לשבור תאימות מקובל מכיוון שהפיצ'ר אינו פונקציונלי כרגע.
אין צורך בשינוי קוד בפונקציה params.get() - היא כבר מחפשת את השם הנכון.
### חלק 2: הוספת פרמטריזציה של Keyspace של Cassandra
#### שינוי 3: הוספת פרמטר Keyspace למודול cassandra_config
**קובץ:** `trustgraph-base/trustgraph/base/cassandra_config.py`
**הוספת ארגומנט שורת פקודה** (בפונקציה `add_cassandra_args()`):
```python
parser.add_argument(
'--cassandra-keyspace',
default=None,
help='Cassandra keyspace (default: service-specific)'
)
```
**הוספת תמיכה במשתני סביבה** (בפונקציה `resolve_cassandra_config()`):
```python
keyspace = params.get(
"cassandra_keyspace",
os.environ.get("CASSANDRA_KEYSPACE")
)
```
**עדכון ערך ההחזרה** של `resolve_cassandra_config()`:
כרגע מחזיר: `(hosts, username, password)`
לשנות כך שיחזיר: `(hosts, username, password, keyspace)`
**הצדקה:**
עקבי עם תבנית התצורה הקיימת של Cassandra
זמין לכל השירותים דרך `add_cassandra_args()`
תומך בתצורה הן דרך שורת הפקודה והן דרך משתני סביבה
#### שינוי 4: שירות תצורה - שימוש במפתחות מרחב (Keyspace) מוגדרים
**קובץ:** `trustgraph-flow/trustgraph/config/service/service.py`
**שורה 30** - הסרת שם מרחב (Keyspace) מקודד:
```python
# DELETE THIS LINE:
keyspace = "config"
```
**שורות 69-73** - עדכון פתרון תצורת Cassandra:
**נוכחי:**
```python
cassandra_host, cassandra_username, cassandra_password = \
resolve_cassandra_config(params)
```
**קבוע:**
```python
cassandra_host, cassandra_username, cassandra_password, keyspace = \
resolve_cassandra_config(params, default_keyspace="config")
```
**הסבר:**
שומר על תאימות לאחור עם "config" כברירת מחדל.
מאפשר ביטול באמצעות `--cassandra-keyspace` או `CASSANDRA_KEYSPACE`.
#### שינוי 5: שירות ליבה/ידע - שימוש במרחבי מפתחות מוגדרים
**קובץ:** `trustgraph-flow/trustgraph/cores/service.py`
**שורה 37** - הסרת מרחב מפתחות מקודד:
```python
# DELETE THIS LINE:
keyspace = "knowledge"
```
**עדכון פתרון תצורת Cassandra** (במיקום דומה לשירות התצורה):
```python
cassandra_host, cassandra_username, cassandra_password, keyspace = \
resolve_cassandra_config(params, default_keyspace="knowledge")
```
#### שינוי 6: שירות סוכן מידע - שימוש במפתחות פרמטריים
**קובץ:** `trustgraph-flow/trustgraph/librarian/service.py`
**שורה 51** - הסרת מרחב מפתחות מקודד:
```python
# DELETE THIS LINE:
keyspace = "librarian"
```
**עדכון פתרון תצורת Cassandra** (במיקום דומה לשירות התצורה):
```python
cassandra_host, cassandra_username, cassandra_password, keyspace = \
resolve_cassandra_config(params, default_keyspace="librarian")
```
### חלק 3: העברת ניהול אוספים לשירות התצורה
#### סקירה כללית
העברת אוספים ממערכת ה-Cassandra librarian keyspace לאחסון בשירות התצורה. פעולה זו מבטלת נושאים מובנים לניהול אחסון ומפשטת את הארכיטקטורה על ידי שימוש במנגנון הדחיפה הקיים של התצורה לצורך הפצה.
#### ארכיטקטורה נוכחית
```
API Request → Gateway → Librarian Service
CollectionManager
Cassandra Collections Table (librarian keyspace)
Broadcast to 4 Storage Management Topics (hardcoded)
Wait for 4+ Storage Service Responses
Response to Gateway
```
#### ארכיטקטורה חדשה
```
API Request → Gateway → Librarian Service
CollectionManager
Config Service API (put/delete/getvalues)
Cassandra Config Table (class='collections', key='user:collection')
Config Push (to all subscribers on config-push-queue)
All Storage Services receive config update independently
```
#### שינוי 7: מנהל אוספים - שימוש ב-API של שירות התצורה
**קובץ:** `trustgraph-flow/trustgraph/librarian/collection_manager.py`
**הסרה:**
שימוש ב-`LibraryTableStore` (שורות 33, 40-41)
אתחול מפיקי ניהול אחסון (שורות 86-140)
שיטה `on_storage_response` (שורות 400-430)
מעקב `pending_deletions` (שורות 57, 90-96 ושימוש לאורך כל הקוד)
**הוספה:**
לקוח שירות תצורה עבור קריאות API (תבנית בקשה/תגובה)
**הגדרת לקוח תצורה:**
```python
# In __init__, add config request/response producers/consumers
from trustgraph.schema.services.config import ConfigRequest, ConfigResponse
# Producer for config requests
self.config_request_producer = Producer(
client=pulsar_client,
topic=config_request_queue,
schema=ConfigRequest,
)
# Consumer for config responses (with correlation ID)
self.config_response_consumer = Consumer(
taskgroup=taskgroup,
client=pulsar_client,
flow=None,
topic=config_response_queue,
subscriber=f"{id}-config",
schema=ConfigResponse,
handler=self.on_config_response,
)
# Tracking for pending config requests
self.pending_config_requests = {} # request_id -> asyncio.Event
```
**שנה את `list_collections` (שורות 145-180):**
```python
async def list_collections(self, user, tag_filter=None, limit=None):
"""List collections from config service"""
# Send getvalues request to config service
request = ConfigRequest(
id=str(uuid.uuid4()),
operation='getvalues',
type='collections',
)
# Send request and wait for response
response = await self.send_config_request(request)
# Parse collections from response
collections = []
for key, value_json in response.values.items():
if ":" in key:
coll_user, collection = key.split(":", 1)
if coll_user == user:
metadata = json.loads(value_json)
collections.append(CollectionMetadata(**metadata))
# Apply tag filtering in-memory (as before)
if tag_filter:
collections = [c for c in collections if any(tag in c.tags for tag in tag_filter)]
# Apply limit
if limit:
collections = collections[:limit]
return collections
async def send_config_request(self, request):
"""Send config request and wait for response"""
event = asyncio.Event()
self.pending_config_requests[request.id] = event
await self.config_request_producer.send(request)
await event.wait()
return self.pending_config_requests.pop(request.id + "_response")
async def on_config_response(self, message, consumer, flow):
"""Handle config response"""
response = message.value()
if response.id in self.pending_config_requests:
self.pending_config_requests[response.id + "_response"] = response
self.pending_config_requests[response.id].set()
```
**שנה את `update_collection` (שורות 182-312):**
```python
async def update_collection(self, user, collection, name, description, tags):
"""Update collection via config service"""
# Create metadata
metadata = CollectionMetadata(
user=user,
collection=collection,
name=name,
description=description,
tags=tags,
)
# Send put request to config service
request = ConfigRequest(
id=str(uuid.uuid4()),
operation='put',
type='collections',
key=f'{user}:{collection}',
value=json.dumps(metadata.to_dict()),
)
response = await self.send_config_request(request)
if response.error:
raise RuntimeError(f"Config update failed: {response.error.message}")
# Config service will trigger config push automatically
# Storage services will receive update and create collections
```
**שנה את `delete_collection` (שורות 314-398):**
```python
async def delete_collection(self, user, collection):
"""Delete collection via config service"""
# Send delete request to config service
request = ConfigRequest(
id=str(uuid.uuid4()),
operation='delete',
type='collections',
key=f'{user}:{collection}',
)
response = await self.send_config_request(request)
if response.error:
raise RuntimeError(f"Config delete failed: {response.error.message}")
# Config service will trigger config push automatically
# Storage services will receive update and delete collections
```
**פורמט מטא-דאטה לאוספים:**
נשמר בטבלת התצורה כ: `class='collections', key='user:collection'`
הערך הוא CollectionMetadata ממוין ב-JSON (ללא שדות תאריך ושעה)
שדות: `user`, `collection`, `name`, `description`, `tags`
דוגמה: `class='collections', key='alice:my-docs', value='{"user":"alice","collection":"my-docs","name":"My Documents","description":"...","tags":["work"]}'`
#### שינוי 8: שירות הספרייה - הסרת תשתית ניהול אחסון
**קובץ:** `trustgraph-flow/trustgraph/librarian/service.py`
**הסרה:**
מפיקי ניהול אחסון (שורות 173-190):
`vector_storage_management_producer`
`object_storage_management_producer`
`triples_storage_management_producer`
צרכן תגובות אחסון (שורות 192-201)
מטפל `on_storage_response` (שורות 467-473)
**שינוי:**
אתחול CollectionManager (שורות 215-224) - הסרת פרמטרים של מפיק אחסון
**הערה:** ממשק ה-API החיצוני לאוספים נשאר ללא שינוי:
`list-collections`
`update-collection`
`delete-collection`
#### שינוי 9: הסרת טבלת האוספים מ-LibraryTableStore
**קובץ:** `trustgraph-flow/trustgraph/tables/library.py`
**מחיקה:**
הצהרת CREATE של טבלת האוספים (שורות 114-127)
הצהרות מוכנות של האוספים (שורות 205-240)
כל שיטות האוספים (שורות 578-717):
`ensure_collection_exists`
`list_collections`
`update_collection`
`delete_collection`
`get_collection`
`create_collection`
**הצדקה:**
האוספים כעת מאוחסנים בטבלת התצורה
שינוי שמשפיע על השינויים - אין צורך בהעברת נתונים
מפשט את שירות הספרייה באופן משמעותי
#### שינוי 10: שירותי אחסון - ניהול אוספים מבוסס תצורה ✅ הושלם
**סטטוס:** כל 11 ה-backends של האחסון עברו לשימוש ב-`CollectionConfigHandler`.
**שירותים מושפעים (סה"כ 11):**
הטמעות מסמכים: milvus, pinecone, qdrant
הטמעות גרפים: milvus, pinecone, qdrant
אחסון אובייקטים: cassandra
אחסון משולשות: cassandra, falkordb, memgraph, neo4j
**קבצים:**
`trustgraph-flow/trustgraph/storage/doc_embeddings/milvus/write.py`
`trustgraph-flow/trustgraph/storage/doc_embeddings/pinecone/write.py`
`trustgraph-flow/trustgraph/storage/doc_embeddings/qdrant/write.py`
`trustgraph-flow/trustgraph/storage/graph_embeddings/milvus/write.py`
`trustgraph-flow/trustgraph/storage/graph_embeddings/pinecone/write.py`
`trustgraph-flow/trustgraph/storage/graph_embeddings/qdrant/write.py`
`trustgraph-flow/trustgraph/storage/objects/cassandra/write.py`
`trustgraph-flow/trustgraph/storage/triples/cassandra/write.py`
`trustgraph-flow/trustgraph/storage/triples/falkordb/write.py`
`trustgraph-flow/trustgraph/storage/triples/memgraph/write.py`
`trustgraph-flow/trustgraph/storage/triples/neo4j/write.py`
**תבנית יישום (לכל השירותים):**
1. **רישום מטפל תצורה ב-`__init__`:**
```python
# Add after AsyncProcessor initialization
self.register_config_handler(self.on_collection_config)
self.known_collections = set() # Track (user, collection) tuples
```
2. **יישום מנהל תצורה:**
```python
async def on_collection_config(self, config, version):
"""Handle collection configuration updates"""
logger.info(f"Collection config version: {version}")
if "collections" not in config:
return
# Parse collections from config
# Key format: "user:collection" in config["collections"]
config_collections = set()
for key in config["collections"].keys():
if ":" in key:
user, collection = key.split(":", 1)
config_collections.add((user, collection))
# Determine changes
to_create = config_collections - self.known_collections
to_delete = self.known_collections - config_collections
# Create new collections (idempotent)
for user, collection in to_create:
try:
await self.create_collection_internal(user, collection)
self.known_collections.add((user, collection))
logger.info(f"Created collection: {user}/{collection}")
except Exception as e:
logger.error(f"Failed to create {user}/{collection}: {e}")
# Delete removed collections (idempotent)
for user, collection in to_delete:
try:
await self.delete_collection_internal(user, collection)
self.known_collections.discard((user, collection))
logger.info(f"Deleted collection: {user}/{collection}")
except Exception as e:
logger.error(f"Failed to delete {user}/{collection}: {e}")
```
3. **אתחול אוספים ידועים בעת ההפעלה:**
```python
async def start(self):
"""Start the processor"""
await super().start()
await self.sync_known_collections()
async def sync_known_collections(self):
"""Query backend to populate known_collections set"""
# Backend-specific implementation:
# - Milvus/Pinecone/Qdrant: List collections/indexes matching naming pattern
# - Cassandra: Query keyspaces or collection metadata
# - Neo4j/Memgraph/FalkorDB: Query CollectionMetadata nodes
pass
```
4. **שכתוב של שיטות טיפול קיימות:**
```python
# Rename and remove response sending:
# handle_create_collection → create_collection_internal
# handle_delete_collection → delete_collection_internal
async def create_collection_internal(self, user, collection):
"""Create collection (idempotent)"""
# Same logic as current handle_create_collection
# But remove response producer calls
# Handle "already exists" gracefully
pass
async def delete_collection_internal(self, user, collection):
"""Delete collection (idempotent)"""
# Same logic as current handle_delete_collection
# But remove response producer calls
# Handle "not found" gracefully
pass
```
5. **הסרת תשתית ניהול אחסון:**
הסרת הגדרות והתחלה של `self.storage_request_consumer`
הסרת הגדרות של `self.storage_response_producer`
הסרת שיטת ה-dispatcher של `on_storage_management`
הסרת מדדים לניהול אחסון
הסרת יבוא: `StorageManagementRequest`, `StorageManagementResponse`
**שיקולים ספציפיים ל-Backend:**
**מאגרי וקטורים (Milvus, Pinecone, Qdrant):** לעקוב אחר `(user, collection)` לוגי ב-`known_collections`, אך ייתכן שייווצרו מספר אוספים ב-backend עבור כל מימד. להמשיך בדפוס היצירה המאוחרת. פעולות מחיקה חייבות להסיר את כל הווריאציות של המימד.
**Cassandra Objects:** אוספים הם מאפייני שורות, ולא מבנים. לעקוב אחר מידע ברמת ה-keyspace.
**מאגרי גרפים (Neo4j, Memgraph, FalkorDB):** לשאול צמתים של `CollectionMetadata` בעת ההפעלה. ליצור/למחוק צמתי מטא-נתונים בעת הסנכרון.
**Cassandra Triples:** להשתמש ב-API של `KnowledgeGraph` עבור פעולות אוסף.
**נקודות עיצוב מרכזיות:**
**עקביות בסופו של דבר:** אין מנגנון בקשה/תגובה, דחיפת תצורה משודרת
**אידמפוטנטיות:** כל פעולות היצירה/מחיקה חייבות להיות בטוחות לניסיון חוזר
**טיפול בשגיאות:** לרשום שגיאות אך לא לחסום עדכוני תצורה
**ריפוי עצמי:** פעולות שנכשלו ינסו שוב בדחיפת התצורה הבאה
**פורמט מפתח אוסף:** `"user:collection"` ב-`config["collections"]`
#### שינוי 11: עדכון סכימת האוסף - הסרת חותמות זמן
**קובץ:** `trustgraph-base/trustgraph/schema/services/collection.py`
**שינוי CollectionMetadata (שורות 13-21):**
להסיר את השדות `created_at` ו-`updated_at`:
```python
class CollectionMetadata(Record):
user = String()
collection = String()
name = String()
description = String()
tags = Array(String())
# Remove: created_at = String()
# Remove: updated_at = String()
```
**שינוי ב-CollectionManagementRequest (שורות 25-47):**
הסרת שדות חותמת זמן:
```python
class CollectionManagementRequest(Record):
operation = String()
user = String()
collection = String()
timestamp = String()
name = String()
description = String()
tags = Array(String())
# Remove: created_at = String()
# Remove: updated_at = String()
tag_filter = Array(String())
limit = Integer()
```
**ההצדקה:**
חותמות זמן אינן מוסיפות ערך לאוספים
שירות התצורה שומר על מעקב גרסאות משלו
מפשט את הסכימה ומקטין את נפח האחסון
#### יתרונות של מעבר לשירות התצורה
1.**מבטל נושאים של ניהול אחסון מקודדים קשות** - פותר את החסימה של ריבוי דיירים
2.**תיאום פשוט יותר** - אין המתנה אסינכרונית מורכבת לתגובות של 4+ שירותי אחסון
3.**עקביות בסופו של דבר** - שירותי האחסון מתעדכנים באופן עצמאי באמצעות דחיפה של תצורה
4.**אמינות טובה יותר** - דחיפה קבועה של תצורה לעומת בקשה/תגובה לא קבועה
5.**מודל תצורה מאוחד** - אוספים מטופלים כתצורה
6.**מפחית מורכבות** - מסיר כ-300 שורות של קוד תיאום
7.**מוכן לריבוי דיירים** - התצורה כבר תומכת בבידוד דיירים באמצעות מרחבי מפתחות
8.**מעקב גרסאות** - מנגנון גרסאות של שירות התצורה מספק תיעוד ביקורת
## הערות יישום
### תאימות לאחור
**שינויים בפרמטרים:**
שינויי שמות של פרמטרים בשורת הפקודה הם שינויים שוברים אך מקובלים (התכונה אינה פונקציונלית כרגע)
השירותים עובדים ללא פרמטרים (משתמשים בברירות המחדל)
מרחבי מפתחות ברירת מחדל נשמרו: "config", "knowledge", "librarian"
תור ברירת מחדל: `persistent://tg/config/config`
**ניהול אוספים:**
**שינוי שובר:** הטבלה של האוספים הוסרה מממרחב המפתחות של librarian
**לא סופקה העברת נתונים** - מקובל לשלב זה
ממשק API חיצוני לאוספים לא השתנה (פעולות רשימה/עדכון/מחיקה)
פורמט מטא-נתונים של אוספים פושט (הוסרו חותמות זמן)
### דרישות בדיקה
**בדיקת פרמטרים:**
1. ודאו שהפרמטר `--config-push-queue` עובד בשירות graph-embeddings
2. ודאו שהפרמטר `--config-push-queue` עובד בשירות text-completion
3. ודאו שהפרמטר `--config-push-queue` עובד בשירות התצורה
4. ודאו שהפרמטר `--cassandra-keyspace` עובד עבור שירות התצורה
5. ודאו שהפרמטר `--cassandra-keyspace` עובד עבור שירות cores
6. ודאו שהפרמטר `--cassandra-keyspace` עובד עבור שירות librarian
7. ודאו שהשירותים עובדים ללא פרמטרים (משתמשים בברירות המחדל)
8. ודאו פריסה מרובת דיירים עם שמות תורים ומרחבי מפתחות מותאמים אישית
**בדיקת ניהול אוספים:**
9. ודאו את הפעולה `list-collections` באמצעות שירות התצורה
10. ודאו ש-`update-collection` יוצר/מעדכן בטבלת התצורה
11. ודאו ש-`delete-collection` מסיר מטבלת התצורה
12. ודאו שדחיפה של תצורה מופעלת בעת עדכונים של אוספים
13. ודאו שסינון תגים עובד עם אחסון מבוסס תצורה
14. ודאו שפעולות על אוספים עובדות ללא שדות חותמות זמן
### דוגמה לפריסה מרובת דיירים
```bash
# Tenant: tg-dev
graph-embeddings \
-p pulsar+ssl://broker:6651 \
--pulsar-api-key <KEY> \
--config-push-queue persistent://tg-dev/config/config
config-service \
-p pulsar+ssl://broker:6651 \
--pulsar-api-key <KEY> \
--config-push-queue persistent://tg-dev/config/config \
--cassandra-keyspace tg_dev_config
```
## ניתוח השפעה
### שירותים המושפעים משינוי 1-2 (שינוי שם פרמטר CLI)
כל השירותים היורשים מ-AsyncProcessor או FlowProcessor:
config-service
cores-service
librarian-service
graph-embeddings
document-embeddings
text-completion-* (כל הספקיות)
extract-* (כל ה-extractors)
query-* (כל שירותי השאילתות)
retrieval-* (כל שירותי ה-RAG)
storage-* (כל שירותי האחסון)
ועוד 20+ שירותים
### שירותים המושפעים משינויים 3-6 (Keyspace של Cassandra)
config-service
cores-service
librarian-service
### שירותים המושפעים משינויים 7-11 (ניהול אוספים)
**שינויים מיידיים:**
librarian-service (collection_manager.py, service.py)
tables/library.py (הסרת טבלת אוספים)
schema/services/collection.py (הסרת חותמת זמן)
**שינויים שהושלמו (שינוי 10):**
כל שירותי האחסון (11 בסך הכל) - עברו ל-config push לעדכוני אוספים דרך `CollectionConfigHandler`
סכימת ניהול האחסון הוסרה מ-`storage.py`
## שיקולים עתידיים
### מודל Keyspace מבוסס משתמש
חלק מהשירותים משתמשים באופן דינמי ב-**keyspace מבוסס משתמש**, כאשר לכל משתמש יש את ה-keyspace של Cassandra שלו:
**שירותים עם keyspace מבוסס משתמש:**
1. **Triples Query Service** (`trustgraph-flow/trustgraph/query/triples/cassandra/service.py:65`)
משתמש ב-`keyspace=query.user`
2. **Objects Query Service** (`trustgraph-flow/trustgraph/query/objects/cassandra/service.py:479`)
משתמש ב-`keyspace=self.sanitize_name(user)`
3. **KnowledgeGraph Direct Access** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py:18`)
פרמטר ברירת מחדל `keyspace="trustgraph"`
**סטטוס:** אלה **לא משתנים** במפרט זה.
**נדרשת בדיקה עתידית:**
להעריך האם מודל ה-keyspace מבוסס משתמש יוצר בעיות בידוד שוכרים
לשקול האם פריסות מרובות שוכרים צריכות דפוסי קידומת keyspace (לדוגמה, `tenant_a_user1`)
לבדוק לגבי התנגשות פוטנציאלית של מזהי משתמש בין שוכרים
להעריך האם keyspace משותף יחיד לכל שוכר עם בידוד שורות מבוסס משתמש עדיף
**הערה:** זה לא חוסם את יישום הריבוי שוכרים הנוכחי, אך יש לבדוק אותו לפני פריסות ריבוי שוכרים לייצור.
## שלבי יישום
### שלב 1: תיקוני פרמטרים (שינויים 1-6)
לתקן את שם הפרמטר `--config-push-queue`
להוסיף תמיכה בפרמטר `--cassandra-keyspace`
**תוצאה:** תצורה של תור ו-keyspace מרובי שוכרים מופעלת
### שלב 2: הגירת ניהול אוספים (שינויים 7-9, 11)
להגר את אחסון האוספים לשירות התצורה
להסיר את טבלת האוספים מ-librarian
לעדכן את סכימת האוספים (להסיר חותמות זמן)
**תוצאה:** מבטלת את נושאי ניהול האחסון המקודדים קשות, מפשטת את librarian
### שלב 3: עדכוני שירותי אחסון (שינוי 10) ✅ הושלם
עדכנו את כל שירותי האחסון להשתמש ב-config push עבור אוספים דרך `CollectionConfigHandler`
הסרנו את תשתית הבקשות/תגובות לניהול אחסון
הסרנו הגדרות סכימה מיושנות
**תוצאה:** השגת ניהול אוספים מבוסס תצורה מלא
## הפניות
GitHub Issue: https://github.com/trustgraph-ai/trustgraph/issues/582
קבצים קשורים:
`trustgraph-base/trustgraph/base/async_processor.py`
`trustgraph-base/trustgraph/base/cassandra_config.py`
`trustgraph-base/trustgraph/schema/core/topic.py`
`trustgraph-base/trustgraph/schema/services/collection.py`
`trustgraph-flow/trustgraph/config/service/service.py`
`trustgraph-flow/trustgraph/cores/service.py`
`trustgraph-flow/trustgraph/librarian/service.py`
`trustgraph-flow/trustgraph/librarian/collection_manager.py`
`trustgraph-flow/trustgraph/tables/library.py`