Documentation Index
Fetch the complete documentation index at: https://platform.docs.zenoo.com/llms.txt
Use this file to discover all available pages before exploring further.
Local Provider
The local provider is a lightweight, in-memory implementation of the cloud provider abstraction designed for local development and testing. It requires zero external dependencies and provides instant startup with no configuration overhead.Overview
The local provider stores all data in memory using thread-safeConcurrentHashMap structures. All data is lost when the application stops, making it ideal for:
- Local Development - Quick iteration without AWS setup
- Integration Testing - Fast, isolated test execution
- CI/CD Pipelines - No external service dependencies
- Prototyping - Rapid experimentation
- Learning - Simple to understand and debug
- Production deployments
- Data persistence across restarts
- Multi-instance deployments (no shared state)
- Large datasets (memory-bound)
Quick Start
1. Add Dependency
Add to yourbuild.gradle:
2. Configure Provider
Add to yourapplication.yml:
3. Start the Hub
The Hub will log:4. Optional Configuration
Configure cleanup and logging (defaults work for most cases):Architecture
Storage Design
The local provider uses Java’sConcurrentHashMap for thread-safe in-memory storage:
Thread Safety
All storage implementations useConcurrentHashMap for thread-safe concurrent access:
- No external locking required
- Safe for multi-threaded request handling
- Atomic operations for consistency
- Read-write locks for complex operations (API key records)
Reactive Support
All operations return Project ReactorMono<T> for consistency with the cloud provider abstraction:
Storage Components
Component Store
Purpose: Store Hub component definitions with versioning Features:- CRUD operations for components
- Revision-based versioning
- LATEST pseudo-revision support
- Metadata and dependency tracking
componentName:revision
Example:
API Key Store
Purpose: Manage API key associations with components Features:- Associate API keys with components
- Track exposed components and functions
- Fast lookup by component name
- Bidirectional sync with ApiKeySecretStorage
API Key Secret Storage
Purpose: Store encrypted API key secrets Features:- Secure secret storage
- Permission-based access control
- Component-level permissions
- Bidirectional sync with ApiKeyStore
Sharable Store
Purpose: Store temporary tokens (magic links, temporary access) Features:- TTL-based expiration
- Lazy expiration (checked on access)
- Optional scheduled cleanup
- Reusable and one-time tokens
- Lazy Expiration: Checked on
get()- expired records are deleted on access - Scheduled Cleanup: Background task removes expired tokens (configurable interval)
Component Config Storage
Purpose: Store component configuration with versioning Features:- Configuration versioning
- LATEST version support
- JSON storage format
- In-memory caching
configId.key:configId.version
Example:
Component Token Service
Purpose: Validate component access tokens Features:- Token-based authentication
- Component permission validation
- Coordinates ApiKeyStore and ApiKeySecretStorage
Configuration Reference
Core Configuration
Local Provider Configuration
Sharable Expiration Configuration
Complete Example Configuration
application-local.yml:Usage Scenarios
Scenario 1: Pure Local Development
Use Case: Developing without any external services Configuration:- Instant startup
- No AWS credentials needed
- No external service dependencies
- Easy to reset (just restart)
- Zero cost
- Data lost on restart
- No persistence
- Single-instance only
Scenario 2: Integration Testing
Use Case: Fast, isolated integration tests Configuration:- Fast test execution
- No test data pollution
- Deterministic behavior
- No external service flakiness
- Parallel test execution
- Use
@DirtiesContextto reset state between tests - Clear stores manually if needed:
localComponentStore.clear() - Use fast cleanup intervals
Scenario 3: CI/CD Pipeline
Use Case: Automated testing in CI/CD Configuration:- No secrets management in CI
- Fast pipeline execution
- No external dependencies
- Consistent behavior
- Cost-free
Scenario 4: Learning and Prototyping
Use Case: Learning Hub DSL and component development Configuration:- Simple to understand
- Easy to debug
- No setup overhead
- Experiment freely
Switching Between Providers
Local -> AWS
To switch from local to AWS provider: Before (Local):Using Profiles for Easy Switching
application-local.yml:Using Environment Variables
Local vs LocalStack vs AWS
| Feature | Local Provider | LocalStack | AWS |
|---|---|---|---|
| Setup | Zero config | Docker setup | AWS account + IAM |
| Startup | Instant | ~10 seconds | Instant (tables exist) |
| Dependencies | None | Docker, LocalStack | AWS credentials |
| Persistence | None | Optional | Full persistence |
| Cost | Free | Free | Pay per use |
| AWS Accuracy | N/A | ~90% | 100% |
| Multi-instance | No | Yes (with config) | Yes |
| Use Case | Quick dev, testing | AWS behavior testing | Production |
When to Use Local Provider
- Quick prototyping and experimentation
- Unit and integration testing
- CI/CD pipelines (no external deps)
- Learning Hub DSL
- No need for persistence
When to Use LocalStack
- Testing AWS-specific features (DynamoDB queries, TTL)
- Validating AWS configuration
- Multi-region testing
- Testing with AWS SDK clients
- Need persistence between restarts
When to Use AWS
- Production deployments
- Staging environments
- Need for data persistence
- Multi-instance deployments
- Compliance requirements
Features
Thread-Safe Concurrent Access
All storage implementations useConcurrentHashMap for safe concurrent access:
- Multiple threads can read/write simultaneously
- No external synchronization required
- Atomic operations guarantee consistency
Reactive Programming Model
All operations returnMono<T> for consistency:
- Integrates with Spring WebFlux
- Non-blocking I/O support
- Composable async operations
Automatic Cleanup
Expired sharables are automatically removed:- Lazy Cleanup: On access, expired items are deleted
- Scheduled Cleanup: Background task runs at configured interval
Versioning Support
Component and configuration versioning with LATEST support: Store specific version:Bidirectional Sync
ApiKeyStore and ApiKeySecretStorage maintain bidirectional sync: When creating a secret:- Secret is stored in ApiKeySecretStorage
- Component association is created in ApiKeyStore
- Secret is removed from ApiKeySecretStorage
- Component association is removed from ApiKeyStore
Limitations
1. No Persistence
All data is lost on application restart:- Components must be redeployed
- Configuration must be recreated
- API keys must be regenerated
- Sharables are lost
2. Single Instance Only
No shared state between multiple Hub instances:- Each instance has its own in-memory storage
- Components registered in one instance are not visible to others
- API keys are not shared
3. Memory-Bound
Storage is limited by available heap memory:- Large component definitions consume memory
- Many API keys increase memory usage
- Long-running instances may accumulate sharables
- Enable automatic cleanup
- Reduce cleanup interval
- Monitor heap usage
- Restart periodically in development
4. No Audit Trail
No logging of storage operations:- Cannot track who created/modified components
- No history of changes
- No compliance audit support
5. No Cross-Region Support
Single JVM, single region only:- No replication
- No failover
- No multi-region deployment
Testing
Unit Tests
Use local provider for fast unit tests:Integration Tests
Clear storage between tests for isolation:Test Utilities
Local stores provide test utilities:Troubleshooting
Components Not Found
Symptom: Component exists butget() returns empty
Causes:
- Component stored with different revision
- Using wrong component name
- Storage was cleared
- Check component ID matches exactly:
ComponentId.of("name", "revision") - Use LATEST if unsure:
ComponentId.of("name", "LATEST") - Enable verbose logging:
hub.local.verboseLogging: true - Check if storage was cleared between tests
Sharables Expired Too Quickly
Symptom: Tokens expire before expected Causes:- Cleanup interval too aggressive
- Expiration set incorrectly
- Time zone issues
- Increase cleanup interval:
hub.local.cleanupInterval: 10m - Check expiration setting:
hub.cloud.provider.sharable.defaultTtl: 24h - Use absolute expiration times in tests
- Disable cleanup in tests:
hub.local.cleanupEnabled: false
Memory Issues
Symptom:OutOfMemoryError after extended runtime
Causes:
- Too many components stored
- Sharables not being cleaned up
- Large component definitions
- Memory leak in application code
- Enable cleanup:
hub.local.cleanupEnabled: true - Reduce cleanup interval:
hub.local.cleanupInterval: 1m - Clear storage periodically:
componentStore.clear() - Increase heap size:
-Xmx2g - Monitor heap usage with JMX
- Profile with VisualVM or JProfiler
Data Lost Between Tests
Symptom: Test fails because data from previous test is missing Causes:- Using
@DirtiesContextbetween tests - Storage cleared in
@BeforeEach - Different Spring context per test
- Share Spring context: Use same test configuration
- Don’t clear storage if data should persist
- Re-populate required data in each test
- Use
@SpringBootTestwith consistent properties
API Keys Not Working
Symptom: API key validation fails Causes:- Secret not created in ApiKeySecretStorage
- Association not created in ApiKeyStore
- Wrong secret name
- Bidirectional sync failed
- Use
ApiKeySecretStorage.create()(handles sync automatically) - Check secret exists:
apiKeySecretStorage.get("key-name") - Check association:
apiKeyStore.getSecrets(componentId) - Enable verbose logging to see sync operations
Advanced Usage
Custom Initialization
Populate storage on startup:Monitoring Storage Size
Track storage size for capacity planning:Exporting Data
Export data for backup or migration:See Also
- Cloud Provider Architecture - Understanding the abstraction layer
- Configuration Reference - All configuration options
- AWS Provider - Production-ready AWS implementation
- Local Development Guide - Local vs LocalStack comparison
- Implementing Providers - Building custom providers