Skip to content

Instantly share code, notes, and snippets.

@futzlarson
Last active April 8, 2026 16:53
Show Gist options
  • Select an option

  • Save futzlarson/1b744b1c6e6b369e17ba173f2c644221 to your computer and use it in GitHub Desktop.

Select an option

Save futzlarson/1b744b1c6e6b369e17ba173f2c644221 to your computer and use it in GitHub Desktop.
Cache invalidation note: rememberForever on master data

Cache Invalidation Note: rememberForever on Master Data

What's cached

Cache Key pattern Used by
CachesIdByName::idByName() App\Models\{Model}:{tenant}:{name} 7 models: MasterTaskStatus, MasterNoteDocStatus, MasterTaskPriority, MasterAssessmentStatus, MasterCaseStatus, MasterCareGapStatus, MasterFileCategory
MasterSmartText::cachedDescriptions() master_smart_texts:{tenant} 20 files — every note, task, assessment, care plan, calendar, and referral form

Both use Cache::rememberForever() with automatic invalidation via Eloquent saved/deleted events.

What depends on these caches

  • idByName() — returns the database ID for a status name (e.g., "Open" → 42). Used for default form values, status checks, filter queries. If stale, forms could default to wrong statuses or filters could return incorrect results.
  • cachedDescriptions() — returns the full smart text name→description map. Used to populate rich text dropdowns in every note/task/assessment form. If stale, dropdowns would show outdated or missing smart text options.

When invalidation works

Any change through the admin UI, Filament forms, or Eloquent model methods — the cache flushes automatically across all tenants.

When it doesn't

Direct DB changes that bypass Eloquent events:

  • DB::table('master_task_statuses')->update(...)
  • Raw SQL in tinker or migrations
  • Bulk imports via upsert() / insert() without model events

In these cases, the cache retains stale data indefinitely.

Risk level

Low. Master data is rarely edited, and almost always through the admin UI. No deploy-time scripts (vapor.yml) touch master tables. No existing ETL jobs or import commands write to these 8 tables.

If it happens

Run php artisan cache:clear — or call the specific flush method:

  • MasterTaskStatus::flushIdByNameCache()
  • MasterSmartText::flushDescriptionsCache()
  • etc.

Decision

Accepted as-is. Adding a TTL fallback would defeat the purpose — these caches eliminate millions of DB queries (3.5M+ hits/2 days for smart text alone). Self-healing via TTL would re-query across all tenants x all names on every expiry cycle.

If any future artisan commands or ETL jobs are built that touch these master tables via DB::table(), they should call the appropriate flush method after completion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment