Service Registry
Dependency injection, service lifecycle, and factory pattern diagrams
Service Registry
This page covers the service registry pattern used for dependency injection, service lifecycle management, and tenant-scoped caching.
Service Registry Architecture
flowchart TB
subgraph "Entry Points"
TRPC[TRPC Router]
API[REST API]
JOB[Background Job]
end
subgraph "Service Registry"
GET_SVC[getService()]
CACHE[Instance Cache]
FACTORY[Service Factories]
end
subgraph "Service Instances"
SVC_A[Product Service]
SVC_B[Order Service]
SVC_C[User Service]
end
subgraph "Dependencies"
DB[Database]
REDIS[Redis]
EXTERNAL[External APIs]
end
TRPC --> GET_SVC
API --> GET_SVC
JOB --> GET_SVC
GET_SVC --> CACHE
CACHE --> FACTORY
FACTORY --> SVC_A
FACTORY --> SVC_B
FACTORY --> SVC_C
SVC_A --> DB
SVC_B --> DB
SVC_C --> DB
SVC_A --> REDIS
SVC_B --> EXTERNAL
style GET_SVC fill:#e1f5fe
style CACHE fill:#e8f5e9Service Lookup Flow
sequenceDiagram
participant Router as TRPC Router
participant Registry as Service Registry
participant Cache as Instance Cache
participant Factory as Service Factory
participant Service as Service Instance
Router->>Registry: getService("product", ctx)
Registry->>Registry: Build cache key
Note over Registry: Key: "product:tenant-uuid"
Registry->>Cache: Check cache
alt Cache hit
Cache-->>Registry: Cached instance
Registry-->>Router: Service instance
else Cache miss
Registry->>Factory: Get factory
Factory->>Factory: Create instance
Factory->>Service: new ProductService(ctx)
Service-->>Factory: Instance
Factory-->>Registry: Instance
Registry->>Cache: Store instance
Registry-->>Router: Service instance
end
Router->>Service: Execute method
Service-->>Router: ResultCache Key Strategy
flowchart TD
SERVICE[Service Request] --> KEY_BUILD[Build Cache Key]
KEY_BUILD --> SCOPE{Service Scope}
SCOPE --> TENANT_SCOPED[Tenant-Scoped]
SCOPE --> SITE_SCOPED[Site-Scoped]
SCOPE --> GLOBAL[Global]
TENANT_SCOPED --> KEY_T["service:tenant:{tenantId}"]
SITE_SCOPED --> KEY_S["service:tenant:{tenantId}:site:{siteId}"]
GLOBAL --> KEY_G["service:global"]
KEY_T --> LOOKUP[Cache Lookup]
KEY_S --> LOOKUP
KEY_G --> LOOKUP
LOOKUP --> HIT{Hit?}
HIT -->|Yes| RETURN[Return Instance]
HIT -->|No| CREATE[Create Instance]
CREATE --> STORE[Store in Cache]
STORE --> RETURN
style RETURN fill:#e8f5e9Service Definition Structure
flowchart TD
subgraph "Definition Files"
DEF_PROD[products.ts]
DEF_ORDER[orders.ts]
DEF_USER[user-management.ts]
DEF_CMS[cms.ts]
end
subgraph "Definition Structure"
KEY[Service Key]
FACTORY[createFactory]
CACHE_KEY[instanceCacheKey]
end
subgraph "Index"
DEFINITIONS[All Definitions]
TYPE_MAP[ServiceMap Type]
end
DEF_PROD --> DEFINITIONS
DEF_ORDER --> DEFINITIONS
DEF_USER --> DEFINITIONS
DEF_CMS --> DEFINITIONS
DEFINITIONS --> KEY
DEFINITIONS --> FACTORY
DEFINITIONS --> CACHE_KEY
DEFINITIONS --> TYPE_MAP
style DEFINITIONS fill:#e8f5e9Factory Pattern
sequenceDiagram
participant Registry as Service Registry
participant Definition as Service Definition
participant Factory as Factory Function
participant Context as Runtime Context
participant Instance as Service Instance
Registry->>Definition: Get service definition
Definition-->>Registry: {createFactory, cacheKey}
Registry->>Definition: createFactory()
Note over Definition: Lazy-loaded async import
Definition->>Factory: Import service module
Factory-->>Definition: createServiceFactory
Definition-->>Registry: Factory function
Registry->>Factory: factory(ctx)
Factory->>Context: Extract tenant info
Context-->>Factory: {tenantId, userId, db}
Factory->>Instance: Create with context
Instance-->>Registry: Service readyService Dependencies
flowchart TD
subgraph "Service Layer"
PRODUCT_SVC[Product Service]
ORDER_SVC[Order Service]
INVENTORY_SVC[Inventory Service]
PAYMENT_SVC[Payment Service]
end
subgraph "Shared Dependencies"
DB_CLIENT[Prisma Client]
CACHE_CLIENT[Redis Client]
EVENT_BUS[Event Bus]
end
subgraph "External Services"
PAYMENT_GW[Payment Gateway]
SHIPPING_API[Shipping API]
EMAIL_SVC[Email Service]
end
PRODUCT_SVC --> DB_CLIENT
PRODUCT_SVC --> CACHE_CLIENT
ORDER_SVC --> DB_CLIENT
ORDER_SVC --> INVENTORY_SVC
ORDER_SVC --> PAYMENT_SVC
INVENTORY_SVC --> DB_CLIENT
INVENTORY_SVC --> EVENT_BUS
PAYMENT_SVC --> PAYMENT_GW
PAYMENT_SVC --> DB_CLIENT
ORDER_SVC --> SHIPPING_API
ORDER_SVC --> EMAIL_SVC
style DB_CLIENT fill:#e1f5feService Lifecycle
stateDiagram-v2
[*] --> UNLOADED: Service Defined
UNLOADED --> LOADING: First Request
LOADING --> READY: Factory Complete
READY --> CACHED: Store in Cache
CACHED --> READY: Cache Hit
CACHED --> EXPIRED: TTL Expired
CACHED --> INVALIDATED: Manual Invalidate
EXPIRED --> UNLOADED: Clear Cache
INVALIDATED --> UNLOADED: Clear Cache
note right of CACHED
Default TTL: 15 minutes
Per-tenant isolation
end noteDomain Organization
flowchart TB
subgraph "E-Commerce Domain"
EC_PROD[product]
EC_ORDER[order]
EC_CART[cart]
EC_PAY[payment]
end
subgraph "CRM Domain"
CRM_CONTACT[contact]
CRM_LEAD[lead]
CRM_OPP[opportunity]
end
subgraph "CMS Domain"
CMS_POST[post]
CMS_PAGE[page]
CMS_MEDIA[media]
end
subgraph "Shipping Domain"
SHIP_LABEL[shipping-label]
SHIP_TRACK[shipment-tracking]
SHIP_CARRIER[carrier]
end
subgraph "Definition Files"
FILE_EC[ecommerce.ts]
FILE_CRM[crm.ts]
FILE_CMS[cms.ts]
FILE_SHIP[shipping.ts]
end
EC_PROD --> FILE_EC
EC_ORDER --> FILE_EC
EC_CART --> FILE_EC
EC_PAY --> FILE_EC
CRM_CONTACT --> FILE_CRM
CRM_LEAD --> FILE_CRM
CRM_OPP --> FILE_CRM
CMS_POST --> FILE_CMS
CMS_PAGE --> FILE_CMS
CMS_MEDIA --> FILE_CMS
SHIP_LABEL --> FILE_SHIP
SHIP_TRACK --> FILE_SHIP
SHIP_CARRIER --> FILE_SHIP
style FILE_EC fill:#e8f5e9
style FILE_CRM fill:#e8f5e9
style FILE_CMS fill:#e8f5e9
style FILE_SHIP fill:#e8f5e9Type Safety
flowchart TD
subgraph "Type Definitions"
KEY_TYPE[ServiceKey Type]
MAP_TYPE[ServiceMap Type]
end
subgraph "Service Keys"
KEY1["'product'"]
KEY2["'order'"]
KEY3["'contact'"]
end
subgraph "Service Types"
TYPE1[ProductService]
TYPE2[OrderService]
TYPE3[ContactService]
end
subgraph "getService Function"
FUNC["getService<K>(key: K, ctx): ServiceMap[K]"]
end
KEY1 --> KEY_TYPE
KEY2 --> KEY_TYPE
KEY3 --> KEY_TYPE
KEY_TYPE --> MAP_TYPE
TYPE1 --> MAP_TYPE
TYPE2 --> MAP_TYPE
TYPE3 --> MAP_TYPE
MAP_TYPE --> FUNC
subgraph "Usage"
USAGE["const svc = await getService('product', ctx)"]
INFERRED["// svc is typed as ProductService"]
end
FUNC --> USAGE
USAGE --> INFERRED
style FUNC fill:#e8f5e9Cache Invalidation
flowchart TD
TRIGGER[Invalidation Trigger] --> TYPE{Trigger Type}
TYPE --> TTL[TTL Expired]
TYPE --> MANUAL[Manual Invalidation]
TYPE --> CONFIG[Config Change]
TYPE --> TENANT[Tenant Switch]
TTL --> AUTOMATIC[Automatic Cleanup]
MANUAL --> SPECIFIC[Specific Service]
MANUAL --> ALL[All Services]
CONFIG --> AFFECTED[Affected Services]
TENANT --> USER_CACHE[User's Service Cache]
AUTOMATIC --> REMOVE[Remove from Cache]
SPECIFIC --> REMOVE
ALL --> CLEAR_ALL[Clear All Cache]
AFFECTED --> REMOVE
USER_CACHE --> REMOVE
REMOVE --> NEXT_REQ[Next Request Creates New]
CLEAR_ALL --> NEXT_REQ
style NEXT_REQ fill:#e8f5e9Memory Management
flowchart TD
subgraph "Without Registry"
REQ1[Request 1] --> NEW1[new Service]
REQ2[Request 2] --> NEW2[new Service]
REQ3[Request 3] --> NEW3[new Service]
NEW1 --> LEAK[Memory Leak!]
NEW2 --> LEAK
NEW3 --> LEAK
end
subgraph "With Registry"
REQ_A[Request 1] --> GET_A[getService]
REQ_B[Request 2] --> GET_B[getService]
REQ_C[Request 3] --> GET_C[getService]
GET_A --> CACHE_INST[Cached Instance]
GET_B --> CACHE_INST
GET_C --> CACHE_INST
CACHE_INST --> CONTROLLED[Controlled Memory]
end
style LEAK fill:#ffebee
style CONTROLLED fill:#e8f5e9Service Registration
sequenceDiagram
participant Dev as Developer
participant Def as Definition File
participant Index as Index Export
participant Types as Type File
participant Registry as Service Registry
Dev->>Def: Add service definition
Note over Def: createFactory, cacheKey
Dev->>Index: Export from index
Note over Index: Merge all definitions
Dev->>Types: Add ServiceKey
Dev->>Types: Add to ServiceMap
Note over Dev,Registry: Build time type checking
Registry->>Index: Import definitions
Registry->>Types: Type inference
Registry->>Registry: Ready for useError Handling
flowchart TD
GET[getService call] --> LOOKUP[Lookup Definition]
LOOKUP --> FOUND{Definition Found?}
FOUND -->|No| ERR_NOT_FOUND[ServiceNotFoundError]
FOUND -->|Yes| FACTORY[Call Factory]
FACTORY --> SUCCESS{Factory Success?}
SUCCESS -->|No| ERR_FACTORY[FactoryError]
SUCCESS -->|Yes| INSTANCE[Return Instance]
INSTANCE --> CACHE_STORE[Store in Cache]
CACHE_STORE --> READY[Service Ready]
ERR_NOT_FOUND --> LOG[Log Error]
ERR_FACTORY --> LOG
LOG --> THROW[Throw Error]
style READY fill:#e8f5e9
style ERR_NOT_FOUND fill:#ffebee
style ERR_FACTORY fill:#ffebeeUsage Pattern
flowchart TD
subgraph "Router Layer"
ROUTER[TRPC Router]
PROC[Procedure Handler]
end
subgraph "Service Access"
GET[getService]
CONTEXT[Request Context]
end
subgraph "Service Layer"
SERVICE[Domain Service]
METHOD[Service Method]
end
subgraph "Data Layer"
DB[Database]
RESULT[Query Result]
end
ROUTER --> PROC
PROC --> GET
GET --> CONTEXT
CONTEXT --> SERVICE
SERVICE --> METHOD
METHOD --> DB
DB --> RESULT
RESULT --> PROC
PROC --> ROUTER
style GET fill:#e8f5e9