QuickDID is a high-performance AT Protocol identity resolution service written in Rust. It provides handle-to-DID resolution with Redis-backed caching and queue processing.

documentation: updating core docs

+7 -2
CLAUDE.md
··· 1 1 # QuickDID - Development Guide for Claude 2 2 3 3 ## Overview 4 - QuickDID is a high-performance AT Protocol identity resolution service written in Rust. It provides handle-to-DID resolution with Redis-backed caching and queue processing. 4 + QuickDID is a high-performance AT Protocol identity resolution service written in Rust. It provides handle-to-DID resolution with multi-layer caching (Redis, SQLite, in-memory), queue processing, metrics support, and proactive cache refreshing. 5 5 6 6 ## Configuration 7 7 ··· 52 52 - `CachingHandleResolver`: In-memory caching layer 53 53 - `RedisHandleResolver`: Redis-backed persistent caching 54 54 - `SqliteHandleResolver`: SQLite-backed persistent caching 55 + - `ProactiveRefreshResolver`: Automatically refreshes cache entries before expiration 55 56 - Uses binary serialization via `HandleResolutionResult` for space efficiency 56 - - Resolution stack: Cache → RateLimited (optional) → Base → DNS/HTTP 57 + - Resolution stack: Cache → ProactiveRefresh (optional) → RateLimited (optional) → Base → DNS/HTTP 57 58 - Includes resolution timing measurements for metrics 58 59 59 60 2. **Binary Serialization** (`src/handle_resolution_result.rs`) ··· 147 148 - `METRICS_STATSD_BIND`: Bind address for StatsD UDP socket (default: [::]:0 for IPv6, can use 0.0.0.0:0 for IPv4) 148 149 - `METRICS_PREFIX`: Prefix for all metrics (default: quickdid) 149 150 - `METRICS_TAGS`: Comma-separated tags (e.g., env:prod,service:quickdid) 151 + 152 + ### Optional - Proactive Refresh 153 + - `PROACTIVE_REFRESH_ENABLED`: Enable proactive cache refreshing (default: false) 154 + - `PROACTIVE_REFRESH_THRESHOLD`: Refresh when TTL remaining is below this threshold (0.0-1.0, default: 0.8) 150 155 151 156 ## Error Handling 152 157
+19 -5
README.md
··· 1 1 # QuickDID 2 2 3 - QuickDID is a high-performance AT Protocol identity resolution service written in Rust. It provides blazing-fast handle-to-DID resolution with intelligent caching strategies, supporting in-memory, Redis-backed, and SQLite-backed persistent caching with binary serialization for optimal storage efficiency. 3 + QuickDID is a high-performance AT Protocol identity resolution service written in Rust. It provides blazing-fast handle-to-DID resolution with intelligent caching strategies, supporting in-memory, Redis-backed, and SQLite-backed persistent caching with binary serialization for optimal storage efficiency. The service includes proactive cache refreshing to maintain optimal performance and comprehensive metrics support for production monitoring. 4 4 5 5 Built following the 12-factor app methodology with minimal dependencies and optimized for production use, QuickDID delivers exceptional performance while maintaining a lean footprint. Configuration is handled exclusively through environment variables, with only `--version` and `--help` command-line arguments supported. 6 6 ··· 41 41 - Resolution timing measurements 42 42 - Configurable tags for environment/service identification 43 43 - Integration guides for Telegraf and TimescaleDB 44 + - Configurable bind address for StatsD UDP socket (IPv4/IPv6) 45 + - **Proactive Cache Refresh**: 46 + - Automatically refreshes cache entries before expiration 47 + - Configurable refresh threshold 48 + - Prevents cache misses for frequently accessed handles 49 + - Metrics tracking for refresh operations 50 + - **Queue Deduplication**: 51 + - Redis-based deduplication for queue items 52 + - Prevents duplicate handle resolution work 53 + - Configurable TTL for deduplication keys 44 54 - **AT Protocol Compatible**: Implements XRPC endpoints for seamless integration with AT Protocol infrastructure 45 55 - **Comprehensive Error Handling**: Structured errors with unique identifiers (e.g., `error-quickdid-config-1`), health checks, and graceful shutdown 46 56 - **12-Factor App**: Environment-based configuration following cloud-native best practices ··· 141 151 - `METRICS_PREFIX`: Prefix for all metrics (default: quickdid) 142 152 - `METRICS_TAGS`: Comma-separated tags (e.g., env:prod,service:quickdid) 143 153 154 + #### Proactive Refresh 155 + - `PROACTIVE_REFRESH_ENABLED`: Enable proactive cache refreshing (default: false) 156 + - `PROACTIVE_REFRESH_THRESHOLD`: Refresh when TTL remaining is below this threshold (0.0-1.0, default: 0.8) 157 + 144 158 #### Logging 145 159 - `RUST_LOG`: Logging level (e.g., debug, info, warn, error) 146 160 ··· 185 199 QuickDID uses a layered architecture for optimal performance: 186 200 187 201 ``` 188 - Request → Cache Layer → Rate Limiter → Base Resolver → DNS/HTTP 189 - ↓ ↓ ↓ 190 - Memory/Redis/ Semaphore AT Protocol 191 - SQLite (optional) Infrastructure 202 + Request → Cache Layer → Proactive Refresh → Rate Limiter → Base Resolver → DNS/HTTP 203 + ↓ ↓ ↓ ↓ 204 + Memory/Redis/ Background Semaphore AT Protocol 205 + SQLite Refresher (optional) Infrastructure 192 206 ``` 193 207 194 208 ### Cache Priority
+261
docs/configuration-reference.md
··· 378 378 QUEUE_REDIS_TIMEOUT=30 # Minimal polling, slow shutdown 379 379 ``` 380 380 381 + ### `QUEUE_REDIS_DEDUP_ENABLED` 382 + 383 + **Required**: No 384 + **Type**: Boolean 385 + **Default**: `false` 386 + 387 + Enable deduplication for Redis queue to prevent duplicate handles from being queued multiple times within the TTL window. When enabled, uses Redis SET with TTL to track handles currently being processed. 388 + 389 + **Examples**: 390 + ```bash 391 + # Enable deduplication (recommended for production) 392 + QUEUE_REDIS_DEDUP_ENABLED=true 393 + 394 + # Disable deduplication (default) 395 + QUEUE_REDIS_DEDUP_ENABLED=false 396 + ``` 397 + 398 + **Use cases**: 399 + - **Production**: Enable to prevent duplicate work and reduce load 400 + - **High-traffic**: Essential to avoid processing the same handle multiple times 401 + - **Development**: Can be disabled for simpler debugging 402 + 403 + ### `QUEUE_REDIS_DEDUP_TTL` 404 + 405 + **Required**: No 406 + **Type**: Integer (seconds) 407 + **Default**: `60` 408 + **Range**: 10-300 (recommended) 409 + **Constraints**: Must be > 0 when deduplication is enabled 410 + 411 + TTL for Redis queue deduplication keys in seconds. Determines how long to prevent duplicate handle resolution requests. 412 + 413 + **Examples**: 414 + ```bash 415 + # Quick deduplication window (10 seconds) 416 + QUEUE_REDIS_DEDUP_TTL=10 417 + 418 + # Default (1 minute) 419 + QUEUE_REDIS_DEDUP_TTL=60 420 + 421 + # Extended deduplication (5 minutes) 422 + QUEUE_REDIS_DEDUP_TTL=300 423 + ``` 424 + 425 + **Recommendations**: 426 + - **Fast processing**: 10-30 seconds 427 + - **Normal processing**: 60 seconds (default) 428 + - **Slow processing or high load**: 120-300 seconds 429 + 381 430 ### `QUEUE_WORKER_ID` 382 431 383 432 **Required**: No ··· 548 597 Rate limit permit acquisition timed out after {timeout}ms 549 598 ``` 550 599 600 + ## Metrics Configuration 601 + 602 + ### `METRICS_ADAPTER` 603 + 604 + **Required**: No 605 + **Type**: String 606 + **Default**: `noop` 607 + **Values**: `noop`, `statsd` 608 + 609 + Metrics adapter type for collecting and publishing metrics. 610 + 611 + **Options**: 612 + - `noop`: No metrics collection (default) 613 + - `statsd`: Send metrics to StatsD server 614 + 615 + **Examples**: 616 + ```bash 617 + # No metrics (default) 618 + METRICS_ADAPTER=noop 619 + 620 + # Enable StatsD metrics 621 + METRICS_ADAPTER=statsd 622 + ``` 623 + 624 + ### `METRICS_STATSD_HOST` 625 + 626 + **Required**: Yes (when METRICS_ADAPTER=statsd) 627 + **Type**: String 628 + **Format**: hostname:port 629 + 630 + StatsD server host and port for metrics collection. 631 + 632 + **Examples**: 633 + ```bash 634 + # Local StatsD 635 + METRICS_STATSD_HOST=localhost:8125 636 + 637 + # Remote StatsD 638 + METRICS_STATSD_HOST=statsd.example.com:8125 639 + 640 + # Docker network 641 + METRICS_STATSD_HOST=statsd:8125 642 + ``` 643 + 644 + ### `METRICS_STATSD_BIND` 645 + 646 + **Required**: No 647 + **Type**: String 648 + **Default**: `[::]:0` 649 + 650 + Bind address for StatsD UDP socket. Controls which local address to bind for sending UDP packets. 651 + 652 + **Examples**: 653 + ```bash 654 + # IPv6 any address, random port (default) 655 + METRICS_STATSD_BIND=[::]:0 656 + 657 + # IPv4 any address, random port 658 + METRICS_STATSD_BIND=0.0.0.0:0 659 + 660 + # Specific interface 661 + METRICS_STATSD_BIND=192.168.1.100:0 662 + 663 + # Specific port 664 + METRICS_STATSD_BIND=[::]:8126 665 + ``` 666 + 667 + ### `METRICS_PREFIX` 668 + 669 + **Required**: No 670 + **Type**: String 671 + **Default**: `quickdid` 672 + 673 + Prefix for all metrics. Used to namespace metrics in your monitoring system. 674 + 675 + **Examples**: 676 + ```bash 677 + # Default 678 + METRICS_PREFIX=quickdid 679 + 680 + # Environment-specific 681 + METRICS_PREFIX=prod.quickdid 682 + METRICS_PREFIX=staging.quickdid 683 + 684 + # Region-specific 685 + METRICS_PREFIX=us-east-1.quickdid 686 + METRICS_PREFIX=eu-west-1.quickdid 687 + 688 + # Service-specific 689 + METRICS_PREFIX=api.quickdid 690 + ``` 691 + 692 + ### `METRICS_TAGS` 693 + 694 + **Required**: No 695 + **Type**: String (comma-separated key:value pairs) 696 + **Default**: None 697 + 698 + Default tags for all metrics. Added to all metrics for filtering and grouping. 699 + 700 + **Examples**: 701 + ```bash 702 + # Basic tags 703 + METRICS_TAGS=env:production,service:quickdid 704 + 705 + # Detailed tags 706 + METRICS_TAGS=env:production,service:quickdid,region:us-east-1,version:1.0.0 707 + 708 + # Deployment-specific 709 + METRICS_TAGS=env:staging,cluster:k8s-staging,namespace:quickdid 710 + ``` 711 + 712 + **Common tag patterns**: 713 + - `env`: Environment (production, staging, development) 714 + - `service`: Service name 715 + - `region`: Geographic region 716 + - `version`: Application version 717 + - `cluster`: Kubernetes cluster name 718 + - `instance`: Instance identifier 719 + 720 + ## Proactive Refresh Configuration 721 + 722 + ### `PROACTIVE_REFRESH_ENABLED` 723 + 724 + **Required**: No 725 + **Type**: Boolean 726 + **Default**: `false` 727 + 728 + Enable proactive cache refresh for frequently accessed handles. When enabled, cache entries that have reached the refresh threshold will be queued for background refresh to keep the cache warm. 729 + 730 + **Examples**: 731 + ```bash 732 + # Enable proactive refresh (recommended for production) 733 + PROACTIVE_REFRESH_ENABLED=true 734 + 735 + # Disable proactive refresh (default) 736 + PROACTIVE_REFRESH_ENABLED=false 737 + ``` 738 + 739 + **Benefits**: 740 + - Prevents cache misses for popular handles 741 + - Maintains consistent response times 742 + - Reduces latency spikes during cache expiration 743 + 744 + **Considerations**: 745 + - Increases background processing load 746 + - More DNS/HTTP requests to upstream services 747 + - Best for high-traffic services with predictable access patterns 748 + 749 + ### `PROACTIVE_REFRESH_THRESHOLD` 750 + 751 + **Required**: No 752 + **Type**: Float 753 + **Default**: `0.8` 754 + **Range**: 0.0-1.0 755 + **Constraints**: Must be between 0.0 and 1.0 756 + 757 + Threshold as a percentage (0.0-1.0) of cache TTL when to trigger proactive refresh. For example, 0.8 means refresh when an entry has lived for 80% of its TTL. 758 + 759 + **Examples**: 760 + ```bash 761 + # Very aggressive (refresh at 50% of TTL) 762 + PROACTIVE_REFRESH_THRESHOLD=0.5 763 + 764 + # Moderate (refresh at 70% of TTL) 765 + PROACTIVE_REFRESH_THRESHOLD=0.7 766 + 767 + # Default (refresh at 80% of TTL) 768 + PROACTIVE_REFRESH_THRESHOLD=0.8 769 + 770 + # Conservative (refresh at 90% of TTL) 771 + PROACTIVE_REFRESH_THRESHOLD=0.9 772 + 773 + # Very conservative (refresh at 95% of TTL) 774 + PROACTIVE_REFRESH_THRESHOLD=0.95 775 + ``` 776 + 777 + **Recommendations**: 778 + - **High-traffic services**: 0.5-0.7 (aggressive refresh) 779 + - **Normal traffic**: 0.8 (default, balanced) 780 + - **Low traffic**: 0.9-0.95 (conservative) 781 + - **Development**: 0.5 (test refresh behavior) 782 + 783 + **Impact on different cache TTLs**: 784 + - TTL=600s (10 min), threshold=0.8: Refresh after 8 minutes 785 + - TTL=3600s (1 hour), threshold=0.8: Refresh after 48 minutes 786 + - TTL=86400s (1 day), threshold=0.8: Refresh after 19.2 hours 787 + 551 788 ## HTTP Caching Configuration 552 789 553 790 ### `CACHE_MAX_AGE` ··· 746 983 QUEUE_ADAPTER=redis 747 984 QUEUE_REDIS_TIMEOUT=5 748 985 QUEUE_BUFFER_SIZE=5000 986 + QUEUE_REDIS_DEDUP_ENABLED=true # Prevent duplicate work 987 + QUEUE_REDIS_DEDUP_TTL=60 749 988 750 989 # Rate Limiting (optional, recommended for production) 751 990 RESOLVER_MAX_CONCURRENT=100 752 991 RESOLVER_MAX_CONCURRENT_TIMEOUT_MS=5000 # 5 second timeout 992 + 993 + # Metrics (optional, recommended for production) 994 + METRICS_ADAPTER=statsd 995 + METRICS_STATSD_HOST=localhost:8125 996 + METRICS_PREFIX=quickdid 997 + METRICS_TAGS=env:prod,service:quickdid 998 + 999 + # Proactive Refresh (optional, recommended for high-traffic) 1000 + PROACTIVE_REFRESH_ENABLED=true 1001 + PROACTIVE_REFRESH_THRESHOLD=0.8 753 1002 754 1003 # HTTP Caching (Cache-Control headers) 755 1004 CACHE_MAX_AGE=86400 # 24 hours ··· 818 1067 QUEUE_REDIS_PREFIX=prod:queue: 819 1068 QUEUE_WORKER_ID=${HOSTNAME:-worker1} 820 1069 QUEUE_REDIS_TIMEOUT=10 1070 + QUEUE_REDIS_DEDUP_ENABLED=true # Essential for multi-instance 1071 + QUEUE_REDIS_DEDUP_TTL=120 # Longer TTL for HA 821 1072 822 1073 # Performance 823 1074 QUEUE_BUFFER_SIZE=10000 ··· 825 1076 # Rate Limiting (important for HA deployments) 826 1077 RESOLVER_MAX_CONCURRENT=500 827 1078 RESOLVER_MAX_CONCURRENT_TIMEOUT_MS=10000 # 10 second timeout for HA 1079 + 1080 + # Metrics (recommended for HA monitoring) 1081 + METRICS_ADAPTER=statsd 1082 + METRICS_STATSD_HOST=statsd:8125 1083 + METRICS_PREFIX=quickdid.prod 1084 + METRICS_TAGS=env:prod,service:quickdid,cluster:ha 1085 + 1086 + # Proactive Refresh (recommended for HA) 1087 + PROACTIVE_REFRESH_ENABLED=true 1088 + PROACTIVE_REFRESH_THRESHOLD=0.7 # More aggressive for HA 828 1089 829 1090 # Logging 830 1091 RUST_LOG=warn
+65
docs/production-deployment.md
··· 133 133 # Higher = less polling overhead, slower shutdown 134 134 QUEUE_REDIS_TIMEOUT=5 135 135 136 + # Enable deduplication for Redis queue to prevent duplicate handles (default: false) 137 + # When enabled, uses Redis SET with TTL to track handles being processed 138 + # Prevents the same handle from being queued multiple times within the TTL window 139 + QUEUE_REDIS_DEDUP_ENABLED=false 140 + 141 + # TTL for Redis queue deduplication keys in seconds (default: 60) 142 + # Range: 10-300 recommended 143 + # Determines how long to prevent duplicate handle resolution requests 144 + QUEUE_REDIS_DEDUP_TTL=60 145 + 136 146 # Worker ID for Redis queue (defaults to "worker1") 137 147 # Set this for predictable worker identification in multi-instance deployments 138 148 # Examples: worker-001, prod-us-east-1, $(hostname) ··· 237 247 # Minimum time response must remain fresh 238 248 # Clients won't accept responses expiring within this time 239 249 CACHE_MIN_FRESH=3600 250 + 251 + # ---------------------------------------------------------------------------- 252 + # METRICS CONFIGURATION 253 + # ---------------------------------------------------------------------------- 254 + 255 + # Metrics adapter type: 'noop' or 'statsd' (default: noop) 256 + # - 'noop': No metrics collection (default) 257 + # - 'statsd': Send metrics to StatsD server 258 + METRICS_ADAPTER=statsd 259 + 260 + # StatsD host and port (required when METRICS_ADAPTER=statsd) 261 + # Format: hostname:port 262 + # Examples: 263 + # - localhost:8125 (local StatsD) 264 + # - statsd.example.com:8125 (remote StatsD) 265 + METRICS_STATSD_HOST=localhost:8125 266 + 267 + # Bind address for StatsD UDP socket (default: [::]:0) 268 + # Controls which local address to bind for sending UDP packets 269 + # Examples: 270 + # - [::]:0 (IPv6 any address, random port - default) 271 + # - 0.0.0.0:0 (IPv4 any address, random port) 272 + # - 192.168.1.100:0 (specific interface) 273 + METRICS_STATSD_BIND=[::]:0 274 + 275 + # Prefix for all metrics (default: quickdid) 276 + # Used to namespace metrics in your monitoring system 277 + # Examples: 278 + # - quickdid (default) 279 + # - prod.quickdid 280 + # - us-east-1.quickdid 281 + METRICS_PREFIX=quickdid 282 + 283 + # Tags for all metrics (comma-separated key:value pairs) 284 + # Added to all metrics for filtering and grouping 285 + # Examples: 286 + # - env:production,service:quickdid 287 + # - env:staging,region:us-east-1,version:1.0.0 288 + METRICS_TAGS=env:production,service:quickdid 289 + 290 + # ---------------------------------------------------------------------------- 291 + # PROACTIVE REFRESH CONFIGURATION 292 + # ---------------------------------------------------------------------------- 293 + 294 + # Enable proactive cache refresh (default: false) 295 + # When enabled, cache entries nearing expiration are automatically refreshed 296 + # in the background to prevent cache misses for frequently accessed handles 297 + PROACTIVE_REFRESH_ENABLED=false 298 + 299 + # Threshold for proactive refresh as percentage of TTL (default: 0.8) 300 + # Range: 0.0-1.0 (0% to 100% of TTL) 301 + # Example: 0.8 means refresh when 80% of TTL has elapsed 302 + # Lower values = more aggressive refreshing, higher load 303 + # Higher values = less aggressive refreshing, more cache misses 304 + PROACTIVE_REFRESH_THRESHOLD=0.8 240 305 241 306 # ---------------------------------------------------------------------------- 242 307 # PERFORMANCE TUNING