RegistrationMetricsDispatcher API
High-performance batching system that collects multiple monitoring tasks generated during registration into a single pipeline.
Overview
RegistrationMetricsDispatcher is WeaveDI's efficient batching layer that consolidates monitoring operations to minimize performance overhead. Instead of executing monitoring tasks immediately upon each registration, it intelligently batches them into pipeline operations for optimal throughput.
Core Features
⚡ Batch Processing
- Task Queuing: Collects multiple monitoring jobs before execution
- Automatic Scheduling: Smart scheduling prevents unnecessary Task spawning
- Utility Priority: Background processing doesn't interfere with main operations
- Memory Efficient: Minimal overhead with job accumulation strategy
🔒 Thread Safety
- NSLock Protection: Thread-safe concurrent job enqueuing
- Atomic Scheduling: Prevents race conditions in batch scheduling
- Safe Flushing: Coordinated batch processing without data races
Performance Characteristics
Efficiency Comparison
| Approach | Task Creation | Context Switches | Memory Pressure |
|---|---|---|---|
| Immediate execution | 1 per registration | High | Medium |
| RegistrationMetricsDispatcher | 1 per batch | Low | Minimal |
Batch Benefits
swift
// Without batching (inefficient)
// Each registration creates separate Task
UnifiedDI.register(ServiceA.self) { ServiceA() } // → Task 1
UnifiedDI.register(ServiceB.self) { ServiceB() } // → Task 2
UnifiedDI.register(ServiceC.self) { ServiceC() } // → Task 3
// With RegistrationMetricsDispatcher (efficient)
// Multiple registrations share single Task
UnifiedDI.register(ServiceA.self) { ServiceA() } // → Queued
UnifiedDI.register(ServiceB.self) { ServiceB() } // → Queued
UnifiedDI.register(ServiceC.self) { ServiceC() } // → Queued + Batch executionInternal Architecture
Core Structure
swift
final class RegistrationMetricsDispatcher: @unchecked Sendable {
typealias Job = @Sendable () async -> Void
static let shared = RegistrationMetricsDispatcher()
private let lock = NSLock()
private var pending: [Job] = []
private var isScheduled = false
}Key Operations
Job Enqueuing
swift
func enqueueRegistration<T>(_ type: T.Type) where T: Sendable {
enqueue { await AutoDIOptimizer.shared.trackRegistration(type) }
}
private func enqueue(_ job: @escaping Job) {
var shouldSchedule = false
lock.lock()
pending.append(job)
if !isScheduled {
isScheduled = true
shouldSchedule = true
}
lock.unlock()
if shouldSchedule {
Task(priority: .utility) {
await self.flush()
}
}
}Batch Processing
swift
private func flush() async {
while true {
let jobs = nextBatch()
if jobs.isEmpty { break }
for job in jobs {
await job()
}
}
}
private func nextBatch() -> [Job] {
lock.lock()
let jobs = pending
pending.removeAll()
if pending.isEmpty {
isScheduled = false
}
lock.unlock()
return jobs
}Integration with WeaveDI
Automatic Usage
swift
// RegistrationMetricsDispatcher is used automatically
let service = UnifiedDI.register(UserService.self) { UserService() }
// Internal flow:
// 1. Registration completes
// 2. RegistrationMetricsDispatcher.shared.enqueueRegistration(UserService.self)
// 3. Job is queued for batch processing
// 4. Background Task processes all queued monitoring jobsPerformance Flow
swift
// Multiple rapid registrations
for i in 1...100 {
UnifiedDI.register(Service\(i).self) { Service\(i)() }
}
// Efficient batching:
// - 100 monitoring jobs queued
// - Single Task spawned for batch processing
// - All jobs processed sequentially in background
// - Minimal impact on registration performanceOptimization Techniques
1. Smart Scheduling
swift
// Only schedule new Task if none is running
if !isScheduled {
isScheduled = true
shouldSchedule = true
}
// → Prevents unnecessary Task creation2. Utility Priority
swift
Task(priority: .utility) {
await self.flush()
}
// → Background processing doesn't block main operations3. Batch Accumulation
swift
// Collect all pending jobs in single operation
let jobs = pending
pending.removeAll()
// → Efficient memory management and processing4. Lock Minimization
swift
lock.lock()
// Minimal work under lock
pending.append(job)
lock.unlock()
// → Reduced lock contentionBest Practices
1. Automatic Operation
swift
// ✅ Good: Dispatcher works automatically
let service = UnifiedDI.register(UserService.self) { UserService() }
// ❌ Avoid: Manual dispatcher usage is unnecessary
// RegistrationMetricsDispatcher.shared.enqueueRegistration(UserService.self)2. High-Volume Registration Patterns
swift
// ✅ Efficient: Batch processing handles high volume
func registerAllServices() {
// All these registrations will be efficiently batched
for serviceType in allServiceTypes {
UnifiedDI.register(serviceType) { createService(serviceType) }
}
}3. Performance Monitoring
swift
// Monitor batch efficiency in development
#if DEBUG
func logBatchMetrics() {
// Batch size and frequency analysis
print("Average batch size: \(averageBatchSize)")
print("Batch frequency: \(batchesPerSecond)")
}
#endifMemory Management
Efficient Memory Usage
- Job Storage: Minimal closure overhead per queued job
- Batch Processing: Immediate job execution and deallocation
- No Accumulation: Jobs don't persist after processing
- Automatic Cleanup: Memory pressure doesn't build up
Memory Footprint
swift
// Actual memory usage per queued job
let jobSize = MemoryLayout<Job>.size // 16 bytes (closure)
// Jobs are processed and deallocated quicklyTechnical Implementation Details
Thread Safety Model
- Enqueue Path: Thread-safe job addition to queue
- Schedule Path: Atomic Task scheduling decision
- Process Path: Sequential job execution in Task
- Cleanup Path: Safe queue reset after processing
Concurrency Patterns
swift
// Thread-safe enqueuing from multiple sources
DispatchQueue.global().async {
UnifiedDI.register(ServiceA.self) { ServiceA() } // Thread 1
}
DispatchQueue.global().async {
UnifiedDI.register(ServiceB.self) { ServiceB() } // Thread 2
}
// Both registrations safely queued and batchedPerformance Optimizations
Batch Size Optimization
- Dynamic Batching: Processes all currently queued jobs
- No Artificial Limits: Natural batching based on registration patterns
- Immediate Processing: Jobs execute as soon as batch is ready
Context Switch Reduction
swift
// Traditional approach: N registrations = N Tasks
// RegistrationMetricsDispatcher: N registrations = 1 Task (batched)
// 50-80% reduction in context switches for high-volume scenariosError Handling
Graceful Degradation
swift
// Individual job failures don't affect batch processing
for job in jobs {
await job() // Each job isolated
}
// → Failed jobs don't break subsequent processingMonitoring Integration
swift
// Integration with AutoDIOptimizer for dependency tracking
enqueue { await AutoDIOptimizer.shared.trackRegistration(type) }
// → Monitoring errors are contained within batch systemReal-World Usage Scenarios
Application Startup
swift
// Efficient handling of bulk dependency registration
class AppDependencySetup {
func registerAllDependencies() {
// 50+ service registrations
registerCoreServices() // → Batched
registerNetworkServices() // → Batched
registerDataServices() // → Batched
registerUIServices() // → Batched
// All monitoring tasks processed in single background Task
}
}Module Loading
swift
// Dynamic module loading with efficient monitoring
func loadModule(_ module: DependencyModule) {
module.dependencies.forEach { dependency in
UnifiedDI.register(dependency.type, factory: dependency.factory)
// → All registrations batched for optimal performance
}
}Comparison with Alternatives
Immediate Execution
swift
// Without RegistrationMetricsDispatcher
UnifiedDI.register(ServiceA.self) {
let service = ServiceA()
Task { await AutoDIOptimizer.shared.trackRegistration(ServiceA.self) } // Task 1
return service
}
UnifiedDI.register(ServiceB.self) {
let service = ServiceB()
Task { await AutoDIOptimizer.shared.trackRegistration(ServiceB.self) } // Task 2
return service
}
// → Multiple Tasks, high overheadWith RegistrationMetricsDispatcher
swift
// With RegistrationMetricsDispatcher
UnifiedDI.register(ServiceA.self) { ServiceA() } // → Queued
UnifiedDI.register(ServiceB.self) { ServiceB() } // → Queued + Batch execute
// → Single Task, minimal overheadSee Also
- AutoDIOptimizer API - Dependency optimization system
- FastResolveCache API - Ultra-fast resolution caching
- UnifiedDI API - Main dependency injection interface
- Performance Monitoring - System performance tracking