Skip to content

Rudimentary impl of dogpile caching - #3011

Merged
whabanks merged 18 commits into
mainfrom
spike/dogpile-cache-get-service
Aug 31, 2026
Merged

Rudimentary impl of dogpile caching#3011
whabanks merged 18 commits into
mainfrom
spike/dogpile-cache-get-service

Conversation

@whabanks

@whabanks whabanks commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Summary | Résumé

This PR implements the basics required to enable dogpile caching in our system. In essence dogpile caches DB responses resulting from DAO method calls; similar to how we cache API responses in Admin, just at the DAO level.

Current progress

  • Add dogpile-cache to pyproject.toml
  • Set up a basic, redis-backed, dogpile cache region with distributed_lock turned on and thread_local_lock turned off to play nicely in a threaded environment
  • Implement a cache-key generation strategy
  • Implement dogpile cached version of dao_fetch_service_by_id
  • Invalidate cache whenever a service's settings are updated Will settle on an invalidation implementation after evaluating the viability of ORM-event hooks vs manually invoking custom invalidation methods. I may be a hybrid of both approaches.

TODO

  • Implement a custom EncodeProxy to support JSON encoding of cache values (it defaults to pickling)
  • Explore different eviction strategies
  • Document findings, pitfalls, caveats, things to keep in mind, etc.

Test instructions | Instructions pour tester la modification

  1. Set FF_USE_DOGPILE_CACHING=true in your .env
  2. Run admin and api locally
  3. From the live services list click on any service
  4. Browse your local redis and note the new cached key:
image

Note: If the cache key didn't appear, you may need to check redis for an service-<id> key and delete it then access that service again to trigger the DB call + dogpile caching.

Release Instructions | Instructions pour le déploiement

None.

Reviewer checklist | Liste de vérification du réviseur

  • This PR does not break existing functionality.
  • This PR does not violate GCNotify's privacy policies.
  • This PR does not raise new security concerns. Refer to our GC Notify Risk Register document on our Google drive.
  • This PR does not significantly alter performance.
  • Additional required documentation resulting of these changes is covered (such as the README, setup instructions, a related ADR or the technical documentation).

⚠ If boxes cannot be checked off before merging the PR, they should be moved to the "Release Instructions" section with appropriate steps required to verify before release. For example, changes to celery code may require tests on staging to verify that performance has not been affected.

- Add dogpile-cache to pyproject.toml
- Set up a basic, redis-backed, dogpile cache region with
  `distributed_lock` turned on and `thread_local_lock` turned off to
play nicely in a threaded environment
- Implement a custom cache-key generation strategy to try and match
  our current cache key patterns
- Implement dogpile cached version of `dao_fetch_service_by_id`
- Invalidate cache whenever a service's settings are updated
Comment thread app/caching.py Fixed
Comment thread app/caching.py Outdated
Comment thread app/service/rest.py Outdated
Instead of implementing per-model/per-dao method invalidation
strategies, implement a broader strategy to allow us to, for example,
invalidate all service related keys when a service is updated.
Comment thread app/caching.py
@whabanks
whabanks marked this pull request as ready for review August 26, 2026 14:53
Copilot AI lite review requested due to automatic review settings August 26, 2026 14:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces a new dogpile.cache-based caching layer (Redis-backed) behind a feature flag, adds custom cache key generation and JSON encoding/decoding helpers, and wires the cached service fetch + invalidation into the service REST endpoints.

Changes:

  • Add dogpile-cache dependency and lockfile updates.
  • Add app.caching module with a configured dogpile region, key generator, serializer/deserializer, and grouped-key invalidation helper.
  • Add feature-flagged use of a cached dao_fetch_service_by_id path and invalidate service-related cache keys on service update.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/app/test_dogpile_caching.py Adds unit tests for dogpile eviction/invalidation patterns, cache key generation, and JSON (de)serialization helpers.
pyproject.toml Adds dogpile-cache dependency (with Redis extra).
poetry.lock Updates lockfile for dogpile-cache and its transitive dependencies.
app/service/rest.py Feature-flagged use of cached service fetch; adds cache invalidation after service updates.
app/dao/services_dao.py Adds a dogpile-cached variant of dao_fetch_service_by_id.
app/config.py Adds FF_USE_DOGPILE_CACHING and dogpile cache config defaults.
app/caching.py New dogpile cache region + key generator + JSON serializer/deserializer + grouped-key invalidation.
app/init.py Initializes the dogpile cache region during app startup.
Suppressed comments (1)

app/dao/services_dao.py:209

  • This cached DAO returns a SQLAlchemy Service instance, but dogpile_region is configured with a JSON serializer/deserializer. Serializing a model object via json.dumps(..., default=str) will store a lossy string representation and subsequent reads will return a string (or wrong shape), breaking service_schema.dump and potentially corrupting cache contents.
    query = Service.query.filter_by(id=service_id).options(joinedload("users"))
    if only_active:
        query = query.filter(Service.active)

    return query.one()

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread app/caching.py Outdated
Comment thread app/service/rest.py Outdated
Comment thread tests/app/test_dogpile_caching.py Outdated
Comment thread app/dao/services_dao.py Outdated
- Remove explicit expiration time from annotations, let region
  configuration propagate
- Ensure tests use the json serializer/deserializer
- Removed explicit call to `invalidate_group_keys` for now
- Default the cache config's REDIS_URL to localhost if not set

@jimleroyer jimleroyer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - this is good to test and go forward. We likely need to experiment on the best setup and get app's team feedback on this. cc @andrewleith

@whabanks
whabanks merged commit 6e9a21b into main Aug 31, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants