92 lines
4.3 KiB
Markdown
92 lines
4.3 KiB
Markdown
# Service Center vs Legacy Services Hub — Comparison & Assessment
|
||
|
||
## Executive Summary
|
||
|
||
The **Service Center** (`modules/serviceCenter`) is a superior architecture compared to the legacy **Services Hub** (`modules/services`). It was worthwhile to create it. The main benefits are: **explicit dependency graph**, **lazy loading**, **per-service RBAC**, and **context-scoped resolution** without carrying the entire hub. The legacy hub remains valid for incremental migration and backward compatibility.
|
||
|
||
---
|
||
|
||
## 1. Architecture Comparison
|
||
|
||
| Aspect | Service Center | Legacy Services Hub |
|
||
|--------|----------------|---------------------|
|
||
| **Location** | `modules/serviceCenter/` | `modules/services/` |
|
||
| **Entry point** | `getService(key, context, legacy_hub)` | `getInterface(user, ...)` → `Services` |
|
||
| **Constructor** | `(context, get_service)` | `(services)` — full hub |
|
||
| **Dependencies** | Declared in registry, resolved lazily via `get_service("key")` | Via `self.services.<attr>` — all services always present |
|
||
| **Loading** | **Lazy** — only requested services + deps | **Eager** — everything at construction |
|
||
| **RBAC** | Per-service `objectKey`, `can_access_service()` | Shared via hub `.rbac` |
|
||
| **Caching** | Per-context cache (user + mandate + featureInstance) | No instance cache — new `Services` each call |
|
||
| **Feature override** | N/A — features use `getService` directly | Feature services override hub attributes |
|
||
| **Pre-warm** | `preWarm()` at app startup | None |
|
||
| **Structure** | Core vs importable split; explicit registry | Flat `serviceX/` dirs; discovery via glob |
|
||
|
||
---
|
||
|
||
## 2. Which Setup is Better?
|
||
|
||
**Service Center is better** for these reasons:
|
||
|
||
### 2.1 Explicit Dependency Graph
|
||
- Dependencies are declared in `registry.py` (e.g. `"ai": {"dependencies": ["chat", "utils", "extraction", "billing"]}`).
|
||
- Circular dependencies are detected and raise `RuntimeError`.
|
||
- Easier to reason about and refactor.
|
||
|
||
### 2.2 Lazy Loading & Resource Efficiency
|
||
- Only requested services (and their transitive deps) are loaded.
|
||
- A feature like chatbot needs `chat`, `ai`, `billing`, `streaming` — not `sharepoint`, `ticket`, `neutralization`, etc.
|
||
- Legacy hub loads **everything** on first `getInterface()`.
|
||
|
||
### 2.3 Context-Scoped Resolution
|
||
- Each request gets a `ServiceCenterContext` (user, mandate_id, feature_instance_id, workflow).
|
||
- Resolution is cached per context. Same user+mandate+feature → same instances.
|
||
- No need to pass or construct a full hub.
|
||
|
||
### 2.4 Per-Service RBAC
|
||
- Services have `objectKey` (e.g. `service.ai`, `service.extraction`).
|
||
- `can_access_service(user, rbac, service_key)` checks before resolving.
|
||
- Finer-grained control than a single hub-level RBAC.
|
||
|
||
### 2.5 Separation of Concerns
|
||
- **Core services** (utils, security, streaming): internal, no RBAC.
|
||
- **Importable services** (ai, billing, extraction, etc.): feature-facing, RBAC-protected.
|
||
- Clear distinction vs. flat structure in legacy.
|
||
|
||
### 2.6 Pre-warm for Cold Start
|
||
- `preWarm()` imports all service modules at startup.
|
||
- First request avoids import latency.
|
||
- Legacy has no equivalent.
|
||
|
||
---
|
||
|
||
## 3. When Legacy Still Makes Sense
|
||
|
||
- **Migration**: Features that haven’t moved yet still use `getInterface()`.
|
||
- **Feature overrides**: Feature-specific services (e.g. `serviceAi/mainServiceAi.py` in a feature) that override hub attributes.
|
||
- **Backward compatibility**: `legacy_hub` fallback in Service Center allows gradual migration.
|
||
|
||
---
|
||
|
||
## 4. Did It Make Sense to Create the Service Center?
|
||
|
||
**Yes.** The legacy hub has inherent limitations:
|
||
|
||
1. **Monolithic hub** — every `getInterface()` constructs a full `Services` object with all services, interfaces, and feature discovery.
|
||
2. **Implicit dependencies** — services grab what they need via `self.services.<attr>`, leading to hidden coupling.
|
||
3. **No explicit RBAC per service** — access control is at the hub level.
|
||
4. **Eager loading** — every request pays for all services even when only a few are used.
|
||
|
||
Service Center addresses these while keeping a migration path via `legacy_hub` fallback. The Chatbot feature already uses it successfully.
|
||
|
||
---
|
||
|
||
## 5. Benchmark Script
|
||
|
||
Run the comparison script to measure runtime and memory:
|
||
|
||
```bash
|
||
# From gateway root
|
||
python tests/benchmarks/benchmark_service_center_vs_legacy.py
|
||
```
|
||
|
||
See `tests/benchmarks/benchmark_service_center_vs_legacy.py` for details on metrics and methodology.
|