When to cache
Problem: You need data from one resource type when processing another (e.g., resolving user IDs to emails when emitting grants). When caching helps:
When NOT to cache:
- Across sync runs (connector restarts clear caches anyway)
- Large datasets that don’t fit in memory
- Data that changes frequently during sync
Thread-safe caching with sync.Map
Problem: Cache data that’s populated in one method and read in another, possibly concurrently. Solution:sync.Map is safe for concurrent reads and writes. The SDK may call different builders concurrently.
Cross-resource lookups
Problem: When emitting grants, you have member IDs but need to determine if they’re users or groups. Solution:Cache warming order
Problem: Grants() runs before the cache is populated. Solution: The SDK processes resource types in the order they’re registered. Register types that populate caches first:Anti-pattern: package-level caches
Real example found in production connectors:- Sync 1 runs, populates cache with users A, B, C
- User B is deleted from the target system
- Sync 2 runs in daemon mode (same process)
- Cache still contains user B
- Grants referencing user B appear valid but point to deleted user
- Access reviews show phantom access that doesn’t exist
Cache lifetime in daemon mode
Problem: In daemon mode, the connector runs continuously processing multiple syncs. Caches need explicit lifetime management. Runtime modes:
Solution: Clear or recreate caches at sync boundaries: