+7
-2
CLAUDE.md
+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
+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
+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
+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