mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-25 16:36:21 +02:00
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.
780 lines
31 KiB
Markdown
780 lines
31 KiB
Markdown
---
|
|
layout: default
|
|
title: "Especificação Técnica: Suporte para Multi-Tenancy"
|
|
parent: "Portuguese (Beta)"
|
|
---
|
|
|
|
# Especificação Técnica: Suporte para Multi-Tenancy
|
|
|
|
> **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.
|
|
|
|
## Visão Geral
|
|
|
|
Habilite implantações multi-tenant corrigindo incompatibilidades de nomes de parâmetros que impedem a personalização da fila e adicionando parametrização do keyspace do Cassandra.
|
|
|
|
## Contexto da Arquitetura
|
|
|
|
### Resolução de Filas Baseada em Fluxo
|
|
|
|
O sistema TrustGraph usa uma **arquitetura baseada em fluxo** para a resolução dinâmica de filas, que suporta inerentemente o multi-tenancy:
|
|
|
|
As **Definições de Fluxo** são armazenadas no Cassandra e especificam os nomes das filas por meio de definições de interface.
|
|
**Os nomes das filas usam modelos** com variáveis `{id}` que são substituídas pelos IDs das instâncias de fluxo.
|
|
**Os serviços resolvem dinamicamente as filas** consultando as configurações de fluxo no momento da solicitação.
|
|
**Cada tenant pode ter fluxos únicos** com nomes de fila diferentes, proporcionando isolamento.
|
|
|
|
Exemplo de definição de interface de fluxo:
|
|
```json
|
|
{
|
|
"interfaces": {
|
|
"triples-store": "persistent://tg/flow/triples-store:{id}",
|
|
"graph-embeddings-store": "persistent://tg/flow/graph-embeddings-store:{id}"
|
|
}
|
|
}
|
|
```
|
|
|
|
Quando o tenant A inicia o fluxo `tenant-a-prod` e o tenant B inicia o fluxo `tenant-b-prod`, eles automaticamente recebem filas isoladas:
|
|
`persistent://tg/flow/triples-store:tenant-a-prod`
|
|
`persistent://tg/flow/triples-store:tenant-b-prod`
|
|
|
|
**Serviços corretamente projetados para multi-tenancy:**
|
|
✅ **Knowledge Management (cores)** - Resolve dinamicamente as filas a partir da configuração do fluxo passada nas requisições
|
|
|
|
**Serviços que precisam de correções:**
|
|
🔴 **Config Service** - Incompatibilidade no nome do parâmetro impede a personalização da fila
|
|
🔴 **Librarian Service** - Tópicos de gerenciamento de armazenamento codificados (discutido abaixo)
|
|
🔴 **Todos os Serviços** - Não é possível personalizar o keyspace do Cassandra
|
|
|
|
## Declaração do Problema
|
|
|
|
### Problema #1: Incompatibilidade no Nome do Parâmetro no AsyncProcessor
|
|
**CLI define:** `--config-queue` (nomeação pouco clara)
|
|
**Argparse converte para:** `config_queue` (no dicionário de parâmetros)
|
|
**Código procura por:** `config_push_queue`
|
|
**Resultado:** O parâmetro é ignorado, usa o valor padrão de `persistent://tg/config/config`
|
|
**Impacto:** Afeta todos os 32+ serviços que herdam do AsyncProcessor
|
|
**Bloqueia:** Impossibilita o uso de filas de configuração específicas do tenant em implantações multi-tenant
|
|
**Solução:** Renomear o parâmetro da CLI para `--config-push-queue` para maior clareza (alteração disruptiva aceitável, já que o recurso está atualmente com defeito)
|
|
|
|
### Problema #2: Incompatibilidade no Nome do Parâmetro no Config Service
|
|
**CLI define:** `--push-queue` (nomeação ambígua)
|
|
**Argparse converte para:** `push_queue` (no dicionário de parâmetros)
|
|
**Código procura por:** `config_push_queue`
|
|
**Resultado:** O parâmetro é ignorado
|
|
**Impacto:** O Config service não pode usar uma fila de push personalizada
|
|
**Solução:** Renomear o parâmetro da CLI para `--config-push-queue` para consistência e clareza (alteração disruptiva aceitável)
|
|
|
|
### Problema #3: Keyspace do Cassandra Codificado
|
|
**Atual:** Keyspace codificado como `"config"`, `"knowledge"`, `"librarian"` em vários serviços
|
|
**Resultado:** Impossibilita a personalização do keyspace para implantações multi-tenant
|
|
**Impacto:** Serviços Config, cores e librarian
|
|
**Bloqueia:** Múltiplos tenants não podem usar keyspaces separados do Cassandra
|
|
|
|
### Problema #4: Arquitetura de Gerenciamento de Coleções ✅ CONCLUÍDO
|
|
**Anterior:** Coleções armazenadas no keyspace do librarian do Cassandra em uma tabela de coleções separada
|
|
**Anterior:** O librarian usava 4 tópicos de gerenciamento de armazenamento codificados para coordenar a criação/exclusão de coleções:
|
|
`vector_storage_management_topic`
|
|
`object_storage_management_topic`
|
|
`triples_storage_management_topic`
|
|
`storage_management_response_topic`
|
|
**Problemas (Resolvidos):**
|
|
Tópicos codificados não podiam ser personalizados para implantações multi-tenant
|
|
Coordenação assíncrona complexa entre o librarian e 4+ serviços de armazenamento
|
|
Tabela separada do Cassandra e infraestrutura de gerenciamento
|
|
Filas de requisição/resposta não persistentes para operações críticas
|
|
**Solução Implementada:** Migrou as coleções para o armazenamento do serviço de configuração, usa push de configuração para distribuição
|
|
**Status:** Todos os backends de armazenamento migrados para o padrão `CollectionConfigHandler`
|
|
|
|
## Solução
|
|
|
|
Esta especificação aborda os problemas #1, #2, #3 e #4.
|
|
|
|
### Parte 1: Corrigir Incompatibilidades no Nome do Parâmetro
|
|
|
|
#### Alteração 1: Classe Base AsyncProcessor - Renomear Parâmetro da CLI
|
|
**Arquivo:** `trustgraph-base/trustgraph/base/async_processor.py`
|
|
**Linha:** 260-264
|
|
|
|
**Atual:**
|
|
```python
|
|
parser.add_argument(
|
|
'--config-queue',
|
|
default=default_config_queue,
|
|
help=f'Config push queue {default_config_queue}',
|
|
)
|
|
```
|
|
|
|
**Corrigido:**
|
|
```python
|
|
parser.add_argument(
|
|
'--config-push-queue',
|
|
default=default_config_queue,
|
|
help=f'Config push queue (default: {default_config_queue})',
|
|
)
|
|
```
|
|
|
|
**Justificativa:**
|
|
Nomenclatura mais clara e explícita
|
|
Coincide com o nome da variável interna `config_push_queue`
|
|
Mudança disruptiva aceitável, já que a funcionalidade está atualmente inativa
|
|
Não é necessária nenhuma alteração no código em params.get() - ele já procura pelo nome correto
|
|
|
|
#### Mudança 2: Serviço de Configuração - Renomear Parâmetro da CLI
|
|
**Arquivo:** `trustgraph-flow/trustgraph/config/service/service.py`
|
|
**Linha:** 276-279
|
|
|
|
**Atual:**
|
|
```python
|
|
parser.add_argument(
|
|
'--push-queue',
|
|
default=default_config_push_queue,
|
|
help=f'Config push queue (default: {default_config_push_queue})'
|
|
)
|
|
```
|
|
|
|
**Corrigido:**
|
|
```python
|
|
parser.add_argument(
|
|
'--config-push-queue',
|
|
default=default_config_push_queue,
|
|
help=f'Config push queue (default: {default_config_push_queue})'
|
|
)
|
|
```
|
|
|
|
**Justificativa:**
|
|
Nomes mais claros - "config-push-queue" é mais explícito do que apenas "push-queue".
|
|
Compatível com o nome da variável interna `config_push_queue`.
|
|
Consistente com o parâmetro `--config-push-queue` do AsyncProcessor.
|
|
Mudança disruptiva aceitável, já que o recurso está atualmente inativo.
|
|
Nenhuma alteração de código necessária em params.get() - ele já procura pelo nome correto.
|
|
|
|
### Parte 2: Adicionar Parametrização do Keyspace do Cassandra
|
|
|
|
#### Mudança 3: Adicionar Parâmetro de Keyspace ao Módulo cassandra_config
|
|
**Arquivo:** `trustgraph-base/trustgraph/base/cassandra_config.py`
|
|
|
|
**Adicionar argumento de linha de comando** (na função `add_cassandra_args()`):
|
|
```python
|
|
parser.add_argument(
|
|
'--cassandra-keyspace',
|
|
default=None,
|
|
help='Cassandra keyspace (default: service-specific)'
|
|
)
|
|
```
|
|
|
|
**Adicionar suporte para variáveis de ambiente** (na função `resolve_cassandra_config()`):
|
|
```python
|
|
keyspace = params.get(
|
|
"cassandra_keyspace",
|
|
os.environ.get("CASSANDRA_KEYSPACE")
|
|
)
|
|
```
|
|
|
|
**Atualizar o valor de retorno** de `resolve_cassandra_config()`:
|
|
Atualmente retorna: `(hosts, username, password)`
|
|
Alterar para retornar: `(hosts, username, password, keyspace)`
|
|
|
|
**Justificativa:**
|
|
Consistente com o padrão de configuração existente do Cassandra
|
|
Disponível para todos os serviços via `add_cassandra_args()`
|
|
Suporta configuração via linha de comando e variáveis de ambiente
|
|
|
|
#### Mudança 4: Serviço de Configuração - Usar Keyspace Parametrizados
|
|
**Arquivo:** `trustgraph-flow/trustgraph/config/service/service.py`
|
|
|
|
**Linha 30** - Remover o keyspace codificado:
|
|
```python
|
|
# DELETE THIS LINE:
|
|
keyspace = "config"
|
|
```
|
|
|
|
**Linhas 69-73** - Atualização da resolução da configuração do Cassandra:
|
|
|
|
**Atual:**
|
|
```python
|
|
cassandra_host, cassandra_username, cassandra_password = \
|
|
resolve_cassandra_config(params)
|
|
```
|
|
|
|
**Corrigido:**
|
|
```python
|
|
cassandra_host, cassandra_username, cassandra_password, keyspace = \
|
|
resolve_cassandra_config(params, default_keyspace="config")
|
|
```
|
|
|
|
**Justificativa:**
|
|
Mantém a compatibilidade com versões anteriores, utilizando "config" como padrão.
|
|
Permite a substituição através de `--cassandra-keyspace` ou `CASSANDRA_KEYSPACE`.
|
|
|
|
#### Mudança 5: Cores/Serviço de Conhecimento - Utilizar Chaves de Espaço de Chaves Parametrizadas
|
|
**Arquivo:** `trustgraph-flow/trustgraph/cores/service.py`
|
|
|
|
**Linha 37** - Remover o espaço de chaves codificado:
|
|
```python
|
|
# DELETE THIS LINE:
|
|
keyspace = "knowledge"
|
|
```
|
|
|
|
**Atualização da resolução de configuração do Cassandra** (localização semelhante ao serviço de configuração):
|
|
```python
|
|
cassandra_host, cassandra_username, cassandra_password, keyspace = \
|
|
resolve_cassandra_config(params, default_keyspace="knowledge")
|
|
```
|
|
|
|
#### Mudança 6: Serviço de Bibliotecário - Use Chaves de Espaço de Chaves Parametrizadas
|
|
**Arquivo:** `trustgraph-flow/trustgraph/librarian/service.py`
|
|
|
|
**Linha 51** - Remova a chave de espaço de chaves codificada:
|
|
```python
|
|
# DELETE THIS LINE:
|
|
keyspace = "librarian"
|
|
```
|
|
|
|
**Atualização da resolução de configuração do Cassandra** (localização semelhante ao serviço de configuração):
|
|
```python
|
|
cassandra_host, cassandra_username, cassandra_password, keyspace = \
|
|
resolve_cassandra_config(params, default_keyspace="librarian")
|
|
```
|
|
|
|
### Parte 3: Migrar o Gerenciamento de Coleções para o Serviço de Configuração
|
|
|
|
#### Visão Geral
|
|
Migrar as coleções do keyspace do Cassandra librarian para o armazenamento do serviço de configuração. Isso elimina os tópicos de gerenciamento de armazenamento codificados e simplifica a arquitetura, utilizando o mecanismo de push de configuração existente para distribuição.
|
|
|
|
#### Arquitetura Atual
|
|
```
|
|
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
|
|
```
|
|
|
|
#### Nova Arquitetura
|
|
```
|
|
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
|
|
```
|
|
|
|
#### Mudança 7: Gerenciador de Coleções - Usar API do Serviço de Configuração
|
|
**Arquivo:** `trustgraph-flow/trustgraph/librarian/collection_manager.py`
|
|
|
|
**Remover:**
|
|
Uso de `LibraryTableStore` (Linhas 33, 40-41)
|
|
Inicialização de produtores de gerenciamento de armazenamento (Linhas 86-140)
|
|
Método `on_storage_response` (Linhas 400-430)
|
|
Rastreamento de `pending_deletions` (Linhas 57, 90-96 e uso em todo o código)
|
|
|
|
**Adicionar:**
|
|
Cliente do serviço de configuração para chamadas de API (padrão de solicitação/resposta)
|
|
|
|
**Configuração do Cliente:**
|
|
```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
|
|
```
|
|
|
|
**Modificar `list_collections` (Linhas 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()
|
|
```
|
|
|
|
**Modificar `update_collection` (Linhas 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
|
|
```
|
|
|
|
**Modificar `delete_collection` (Linhas 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
|
|
```
|
|
|
|
**Formato de Metadados de Coleção:**
|
|
Armazenado na tabela de configuração como: `class='collections', key='user:collection'`
|
|
O valor é uma CollectionMetadata serializada em JSON (sem campos de timestamp)
|
|
Campos: `user`, `collection`, `name`, `description`, `tags`
|
|
Exemplo: `class='collections', key='alice:my-docs', value='{"user":"alice","collection":"my-docs","name":"My Documents","description":"...","tags":["work"]}'`
|
|
|
|
#### Mudança 8: Serviço de Bibliotecário - Remover a Infraestrutura de Gerenciamento de Armazenamento
|
|
**Arquivo:** `trustgraph-flow/trustgraph/librarian/service.py`
|
|
|
|
**Remover:**
|
|
Produtores de gerenciamento de armazenamento (Linhas 173-190):
|
|
`vector_storage_management_producer`
|
|
`object_storage_management_producer`
|
|
`triples_storage_management_producer`
|
|
Consumidor de resposta de armazenamento (Linhas 192-201)
|
|
Manipulador `on_storage_response` (Linhas 467-473)
|
|
|
|
**Modificar:**
|
|
Inicialização do CollectionManager (Linhas 215-224) - remover os parâmetros do produtor de armazenamento
|
|
|
|
**Observação:** A API externa de coleções permanece inalterada:
|
|
`list-collections`
|
|
`update-collection`
|
|
`delete-collection`
|
|
|
|
#### Mudança 9: Remover a Tabela de Coleções do LibraryTableStore
|
|
**Arquivo:** `trustgraph-flow/trustgraph/tables/library.py`
|
|
|
|
**Excluir:**
|
|
Instrução CREATE da tabela de coleções (Linhas 114-127)
|
|
Prepared statements de coleções (Linhas 205-240)
|
|
Todos os métodos de coleção (Linhas 578-717):
|
|
`ensure_collection_exists`
|
|
`list_collections`
|
|
`update_collection`
|
|
`delete_collection`
|
|
`get_collection`
|
|
`create_collection`
|
|
|
|
**Justificativa:**
|
|
As coleções agora são armazenadas na tabela de configuração
|
|
Mudança disruptiva aceitável - nenhuma migração de dados necessária
|
|
Simplifica significativamente o serviço de bibliotecário
|
|
|
|
#### Mudança 10: Serviços de Armazenamento - Gerenciamento de Coleção Baseado em Configuração ✅ CONCLUÍDO
|
|
|
|
**Status:** Todos os 11 backends de armazenamento foram migrados para usar `CollectionConfigHandler`.
|
|
|
|
**Serviços Afetados (11 no total):**
|
|
Embeddings de documentos: milvus, pinecone, qdrant
|
|
Embeddings de grafos: milvus, pinecone, qdrant
|
|
Armazenamento de objetos: cassandra
|
|
Armazenamento de triplas: cassandra, falkordb, memgraph, neo4j
|
|
|
|
**Arquivos:**
|
|
`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`
|
|
|
|
**Padrão de Implementação (todos os serviços):**
|
|
|
|
1. **Registrar o manipulador de configuração em `__init__`:**
|
|
```python
|
|
# Add after AsyncProcessor initialization
|
|
self.register_config_handler(self.on_collection_config)
|
|
self.known_collections = set() # Track (user, collection) tuples
|
|
```
|
|
|
|
2. **Implementar o gerenciador de configuração:**
|
|
```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. **Inicialize as coleções conhecidas na inicialização:**
|
|
```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. **Refatore os métodos de tratamento existentes:**
|
|
```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. **Remover a infraestrutura de gerenciamento de armazenamento:**
|
|
Remover a configuração e inicialização de `self.storage_request_consumer`
|
|
Remover a configuração de `self.storage_response_producer`
|
|
Remover o método de dispatcher de `on_storage_management`
|
|
Remover as métricas para o gerenciamento de armazenamento
|
|
Remover as importações: `StorageManagementRequest`, `StorageManagementResponse`
|
|
|
|
**Considerações Específicas para o Backend:**
|
|
|
|
**Bancos de dados vetoriais (Milvus, Pinecone, Qdrant):** Rastrear a lógica `(user, collection)` em `known_collections`, mas pode criar múltiplas coleções de backend por dimensão. Continuar o padrão de criação preguiçosa. As operações de exclusão devem remover todas as variantes de dimensão.
|
|
|
|
**Cassandra Objects:** As coleções são propriedades de linha, não estruturas. Rastrear informações no nível do keyspace.
|
|
|
|
**Bancos de dados de grafos (Neo4j, Memgraph, FalkorDB):** Consultar nós `CollectionMetadata` na inicialização. Criar/excluir nós de metadados na sincronização.
|
|
|
|
**Cassandra Triples:** Usar a API `KnowledgeGraph` para operações de coleção.
|
|
|
|
**Pontos-Chave do Design:**
|
|
|
|
**Consistência eventual:** Não há mecanismo de solicitação/resposta, o envio de configuração é transmitido.
|
|
**Idempotência:** Todas as operações de criação/exclusão devem ser seguras para serem repetidas.
|
|
**Tratamento de erros:** Registrar erros, mas não bloquear as atualizações de configuração.
|
|
**Autorreparação:** As operações com falha serão repetidas na próxima atualização de configuração.
|
|
**Formato da chave da coleção:** `"user:collection"` em `config["collections"]`
|
|
|
|
#### Mudança 11: Atualizar o Esquema da Coleção - Remover Timestamps
|
|
**Arquivo:** `trustgraph-base/trustgraph/schema/services/collection.py`
|
|
|
|
**Modificar CollectionMetadata (Linhas 13-21):**
|
|
Remover os campos `created_at` e `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()
|
|
```
|
|
|
|
**Modificar CollectionManagementRequest (linhas 25-47):**
|
|
Remover campos de timestamp:
|
|
```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()
|
|
```
|
|
|
|
**Justificativa:**
|
|
Os carimbos de data e hora não agregam valor para coleções.
|
|
O serviço de configuração mantém seu próprio rastreamento de versão.
|
|
Simplifica o esquema e reduz o armazenamento.
|
|
|
|
#### Benefícios da Migração do Serviço de Configuração
|
|
|
|
1. ✅ **Elimina tópicos de gerenciamento de armazenamento codificados** - Resolve o bloqueio multi-inquilino.
|
|
2. ✅ **Coordenação mais simples** - Sem espera assíncrona complexa por 4 ou mais respostas de armazenamento.
|
|
3. ✅ **Consistência eventual** - Os serviços de armazenamento são atualizados independentemente por meio de push de configuração.
|
|
4. ✅ **Melhor confiabilidade** - Push de configuração persistente versus solicitação/resposta não persistente.
|
|
5. ✅ **Modelo de configuração unificado** - Coleções tratadas como configuração.
|
|
6. ✅ **Reduz a complexidade** - Remove aproximadamente 300 linhas de código de coordenação.
|
|
7. ✅ **Pronto para multi-inquilino** - A configuração já suporta o isolamento de inquilinos por meio de keyspace.
|
|
8. ✅ **Rastreamento de versão** - O mecanismo de versão do serviço de configuração fornece um histórico de auditoria.
|
|
|
|
## Notas de Implementação
|
|
|
|
### Compatibilidade com versões anteriores
|
|
|
|
**Alterações de parâmetros:**
|
|
As alterações de nome dos parâmetros da CLI são alterações disruptivas, mas aceitáveis (o recurso atualmente não está funcional).
|
|
Os serviços funcionam sem parâmetros (use os padrões).
|
|
Keyspaces padrão preservados: "config", "knowledge", "librarian".
|
|
Fila padrão: `persistent://tg/config/config`
|
|
|
|
**Gerenciamento de coleções:**
|
|
**Alteração disruptiva:** A tabela de coleções foi removida do keyspace librarian.
|
|
**Nenhuma migração de dados fornecida** - aceitável para esta fase.
|
|
A API de coleção externa não foi alterada (operações de listagem, atualização e exclusão).
|
|
O formato de metadados da coleção foi simplificado (os carimbos de data e hora foram removidos).
|
|
|
|
### Requisitos de teste
|
|
|
|
**Teste de parâmetros:**
|
|
1. Verificar se o parâmetro `--config-push-queue` funciona no serviço graph-embeddings.
|
|
2. Verificar se o parâmetro `--config-push-queue` funciona no serviço text-completion.
|
|
3. Verificar se o parâmetro `--config-push-queue` funciona no serviço de configuração.
|
|
4. Verificar se o parâmetro `--cassandra-keyspace` funciona para o serviço de configuração.
|
|
5. Verificar se o parâmetro `--cassandra-keyspace` funciona para o serviço cores.
|
|
6. Verificar se o parâmetro `--cassandra-keyspace` funciona para o serviço librarian.
|
|
7. Verificar se os serviços funcionam sem parâmetros (usa os padrões).
|
|
8. Verificar a implantação multi-inquilino com nomes de fila e keyspace personalizados.
|
|
|
|
**Teste de gerenciamento de coleções:**
|
|
9. Verificar a operação `list-collections` por meio do serviço de configuração.
|
|
10. Verificar se `update-collection` cria/atualiza na tabela de configuração.
|
|
11. Verificar se `delete-collection` remove da tabela de configuração.
|
|
12. Verificar se o push de configuração é acionado em atualizações de coleção.
|
|
13. Verificar se a filtragem de tags funciona com armazenamento baseado em configuração.
|
|
14. Verificar se as operações de coleção funcionam sem campos de carimbo de data e hora.
|
|
|
|
### Exemplo de implantação multi-inquilino
|
|
```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
|
|
```
|
|
|
|
## Análise de Impacto
|
|
|
|
### Serviços Afetados pela Alteração 1-2 (Renomeação de Parâmetro da CLI)
|
|
Todos os serviços que herdam de AsyncProcessor ou FlowProcessor:
|
|
config-service
|
|
cores-service
|
|
librarian-service
|
|
graph-embeddings
|
|
document-embeddings
|
|
text-completion-* (todos os provedores)
|
|
extract-* (todos os extractors)
|
|
query-* (todos os serviços de consulta)
|
|
retrieval-* (todos os serviços RAG)
|
|
storage-* (todos os serviços de armazenamento)
|
|
E mais 20 serviços
|
|
|
|
### Serviços Afetados pelas Alterações 3-6 (Keyspace do Cassandra)
|
|
config-service
|
|
cores-service
|
|
librarian-service
|
|
|
|
### Serviços Afetados pelas Alterações 7-11 (Gerenciamento de Coleções)
|
|
|
|
**Alterações Imediatas:**
|
|
librarian-service (collection_manager.py, service.py)
|
|
tables/library.py (remoção da tabela de coleções)
|
|
schema/services/collection.py (remoção do timestamp)
|
|
|
|
**Alterações Concluídas (Alteração 10):** ✅
|
|
Todos os serviços de armazenamento (11 no total) - migrados para o push de configuração para atualizações de coleções via `CollectionConfigHandler`
|
|
Esquema de gerenciamento de armazenamento removido de `storage.py`
|
|
|
|
## Considerações Futuras
|
|
|
|
### Modelo de Keyspace por Usuário
|
|
|
|
Alguns serviços usam **keyspaces por usuário** dinamicamente, onde cada usuário recebe seu próprio keyspace do Cassandra:
|
|
|
|
**Serviços com keyspaces por usuário:**
|
|
1. **Triples Query Service** (`trustgraph-flow/trustgraph/query/triples/cassandra/service.py:65`)
|
|
Usa `keyspace=query.user`
|
|
2. **Objects Query Service** (`trustgraph-flow/trustgraph/query/objects/cassandra/service.py:479`)
|
|
Usa `keyspace=self.sanitize_name(user)`
|
|
3. **KnowledgeGraph Direct Access** (`trustgraph-flow/trustgraph/direct/cassandra_kg.py:18`)
|
|
Parâmetro padrão `keyspace="trustgraph"`
|
|
|
|
**Status:** Estes **não são modificados** nesta especificação.
|
|
|
|
**Revisão Futura Necessária:**
|
|
Avaliar se o modelo de keyspace por usuário cria problemas de isolamento de locatários
|
|
Considerar se as implementações multi-locatário precisam de padrões de prefixo de keyspace (por exemplo, `tenant_a_user1`)
|
|
Revisar para possíveis colisões de ID de usuário entre locatários
|
|
Avaliar se um keyspace compartilhado único por locatário com isolamento de linha baseado em usuário é preferível
|
|
|
|
**Observação:** Isso não impede a implementação multi-locatário atual, mas deve ser revisado antes das implementações multi-locatário de produção.
|
|
|
|
## Fases de Implementação
|
|
|
|
### Fase 1: Correções de Parâmetros (Alterações 1-6)
|
|
Corrigir a nomenclatura do parâmetro `--config-push-queue`
|
|
Adicionar suporte ao parâmetro `--cassandra-keyspace`
|
|
**Resultado:** Configuração de fila e keyspace multi-locatário habilitada
|
|
|
|
### Fase 2: Migração do Gerenciamento de Coleções (Alterações 7-9, 11)
|
|
Migrar o armazenamento de coleções para o serviço de configuração
|
|
Remover a tabela de coleções do librarian
|
|
Atualizar o esquema de coleção (remover timestamps)
|
|
**Resultado:** Elimina tópicos de gerenciamento de armazenamento codificados, simplifica o librarian
|
|
|
|
### Fase 3: Atualizações do Serviço de Armazenamento (Alteração 10) ✅ CONCLUÍDA
|
|
Atualizados todos os serviços de armazenamento para usar o push de configuração para coleções via `CollectionConfigHandler`
|
|
Removida a infraestrutura de solicitação/resposta de gerenciamento de armazenamento
|
|
Removidas as definições de esquema legadas
|
|
**Resultado:** Gerenciamento de coleções baseado em configuração completo alcançado
|
|
|
|
## Referências
|
|
GitHub Issue: https://github.com/trustgraph-ai/trustgraph/issues/582
|
|
Arquivos Relacionados:
|
|
`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`
|