Commit 60e6dbc
authored
Closes #792. Follow-up to #788.
## Summary
The per-site `invalidate*` helpers in `api/issues.ts`,
`api/projects.ts`, and `api/dashboards.ts` are replaced by a single
post-mutation hook in `authenticatedFetch` that auto-invalidates the
cache for every successful non-GET. Prefix computation lives in a new
`src/lib/cache-keys.ts` module.
## Layer 1: HTTP-layer hook (new)
`invalidateAfterMutation` fires after `fetchWithRetry` returns a 2xx
non-GET response:
- **Hierarchy walk** — for
`/api/0/organizations/{org}/releases/1.0.0/deploys/`, sweeps the URL
path plus every ancestor down to the owner level (`releases/1.0.0/`,
`releases/`, `organizations/{org}/`). The bare top-level
`organizations/` root is deliberately **not** swept — sweeping it on
every mutation would evict unrelated cross-org caches.
- **Cross-endpoint rules** — tiny table for the 2 cases where a mutation
affects a different URL tree:
- `POST /api/0/teams/{org}/{team}/projects/` invalidates
`/api/0/organizations/{org}/projects/`
- `DELETE /api/0/projects/{org}/{project}/` invalidates
`/api/0/organizations/{org}/projects/`
- **Write-only endpoints skip invalidation** — sourcemap chunk uploads
and artifact-bundle assembly don't modify any cacheable state, so
they're short-circuited at the top of `computeInvalidationPrefixes`.
Without this, every chunk of a sourcemap upload (hundreds of POSTs at
N-way concurrency) would sweep the org's cache.
The hook is **awaited** before returning the response, so a subsequent
read in the same command sees fresh data. Identity-gated via the
existing sweep primitive (no cross-account eviction).
## Layer 2: Command-level override (deferred)
Issue #792 proposed an optional `invalidates` callback on `buildCommand`
for cross-endpoint fan-outs the HTTP layer can't know about. Turned out
the 2 hardcoded rules above cover every current case — deferred the
callback API to when a real use case emerges.
## Coverage
Every mutation in `src/lib/api/` is now covered for free, including ones
that had no invalidation before:
- `release create/update/delete`, `release deploy`, `set-commits*`
- `team create`, `member add`
- `dashboard create`
- `trial start`
`sentry api -X POST/PUT/DELETE ...` also gets auto-invalidation — users
of the raw escape hatch no longer need `--fresh` on follow-up reads.
## Removed
- `api/issues.ts`: `invalidateIssueCaches`,
`invalidateIssueDetailCaches`, `invalidateOrgIssueList` + their call
sites in `updateIssueStatus` / `mergeIssues`.
- `api/projects.ts`: `invalidateProjectCaches`,
`invalidateOrgProjectCache` + call sites in `createProject` /
`deleteProject`.
- `api/dashboards.ts`: inline `invalidateCachedResponse` in
`updateDashboard`.
## Tests
- `test/lib/cache-keys.test.ts` — 15 tests: hierarchy walk (with the
owner-level cap), cross-endpoint rules, write-only skip, query-string
stripping, unparseable URLs, self-hosted bases, dedup.
- `test/lib/sentry-client.invalidation.test.ts` — 5 integration tests:
successful mutation clears self + list, failed mutation leaves cache
alone, GET doesn't invalidate, cross-endpoint rule fires, identity
isolation holds.
Full unit suite: 5706 passing. `bun run typecheck`, `bun run lint`
clean.
## Follow-ups
One minor optimization deferred: when the hook computes multiple
prefixes, `Promise.all` kicks off independent
`invalidateCachedResponsesMatching` calls, each doing its own `readdir`
+ per-file parse. For typical cache sizes (few hundred entries) this is
negligible, but the natural shape is "read the dir once, match every
entry against ALL prefixes, unlink if any match." A future
`invalidateCachedResponsesMatchingAny(prefixes: string[])` API would
eliminate the redundant I/O. Not done here to keep the PR scoped.
1 parent 3d71685 commit 60e6dbc
12 files changed
Lines changed: 631 additions & 234 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
27 | 27 | | |
28 | 28 | | |
29 | 29 | | |
30 | | - | |
31 | 30 | | |
32 | 31 | | |
33 | 32 | | |
| |||
125 | 124 | | |
126 | 125 | | |
127 | 126 | | |
128 | | - | |
129 | | - | |
130 | | - | |
131 | | - | |
132 | | - | |
133 | | - | |
134 | | - | |
135 | | - | |
136 | 127 | | |
137 | 128 | | |
138 | 129 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
179 | 179 | | |
180 | 180 | | |
181 | 181 | | |
182 | | - | |
183 | | - | |
184 | | - | |
185 | | - | |
186 | | - | |
187 | | - | |
188 | | - | |
189 | | - | |
190 | | - | |
191 | | - | |
192 | | - | |
193 | | - | |
194 | | - | |
195 | | - | |
196 | | - | |
197 | | - | |
198 | | - | |
199 | | - | |
200 | | - | |
201 | | - | |
202 | | - | |
203 | 182 | | |
204 | 183 | | |
205 | 184 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
19 | 19 | | |
20 | 20 | | |
21 | 21 | | |
22 | | - | |
23 | 22 | | |
24 | 23 | | |
25 | 24 | | |
26 | 25 | | |
27 | 26 | | |
28 | 27 | | |
| 28 | + | |
| 29 | + | |
29 | 30 | | |
30 | 31 | | |
31 | 32 | | |
| |||
566 | 567 | | |
567 | 568 | | |
568 | 569 | | |
569 | | - | |
570 | 570 | | |
571 | 571 | | |
572 | 572 | | |
573 | | - | |
574 | | - | |
575 | | - | |
576 | | - | |
577 | | - | |
578 | | - | |
579 | | - | |
580 | | - | |
581 | | - | |
582 | | - | |
583 | | - | |
584 | | - | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
| 576 | + | |
| 577 | + | |
585 | 578 | | |
586 | 579 | | |
587 | 580 | | |
| |||
625 | 618 | | |
626 | 619 | | |
627 | 620 | | |
628 | | - | |
629 | | - | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
630 | 628 | | |
631 | 629 | | |
632 | 630 | | |
633 | | - | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
634 | 634 | | |
635 | 635 | | |
636 | | - | |
637 | 636 | | |
638 | 637 | | |
639 | 638 | | |
| |||
693 | 692 | | |
694 | 693 | | |
695 | 694 | | |
696 | | - | |
697 | | - | |
698 | | - | |
699 | | - | |
700 | | - | |
701 | | - | |
702 | | - | |
703 | | - | |
704 | | - | |
705 | | - | |
706 | | - | |
707 | | - | |
708 | | - | |
709 | | - | |
710 | | - | |
711 | | - | |
712 | | - | |
713 | | - | |
714 | | - | |
715 | | - | |
716 | | - | |
717 | | - | |
718 | | - | |
719 | | - | |
720 | | - | |
721 | | - | |
722 | | - | |
723 | | - | |
724 | | - | |
725 | | - | |
726 | | - | |
727 | | - | |
728 | | - | |
729 | | - | |
730 | | - | |
731 | | - | |
732 | | - | |
733 | | - | |
734 | | - | |
735 | | - | |
736 | | - | |
737 | | - | |
738 | | - | |
739 | | - | |
740 | | - | |
741 | | - | |
742 | | - | |
743 | | - | |
744 | | - | |
745 | | - | |
746 | | - | |
747 | | - | |
748 | | - | |
749 | | - | |
750 | | - | |
751 | | - | |
752 | | - | |
753 | | - | |
754 | | - | |
755 | | - | |
756 | | - | |
757 | | - | |
758 | | - | |
759 | | - | |
760 | | - | |
761 | | - | |
762 | | - | |
763 | | - | |
764 | | - | |
765 | | - | |
766 | | - | |
767 | | - | |
768 | | - | |
769 | | - | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
29 | | - | |
30 | 28 | | |
31 | 29 | | |
32 | 30 | | |
33 | 31 | | |
34 | 32 | | |
35 | 33 | | |
36 | 34 | | |
37 | | - | |
38 | 35 | | |
39 | 36 | | |
40 | 37 | | |
| |||
169 | 166 | | |
170 | 167 | | |
171 | 168 | | |
172 | | - | |
173 | 169 | | |
174 | 170 | | |
175 | 171 | | |
| |||
219 | 215 | | |
220 | 216 | | |
221 | 217 | | |
222 | | - | |
223 | | - | |
224 | | - | |
225 | | - | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
231 | | - | |
232 | | - | |
233 | | - | |
234 | | - | |
235 | | - | |
236 | | - | |
237 | | - | |
238 | | - | |
239 | | - | |
240 | | - | |
241 | | - | |
242 | | - | |
243 | | - | |
244 | | - | |
245 | | - | |
246 | | - | |
247 | | - | |
248 | | - | |
249 | | - | |
250 | | - | |
251 | | - | |
252 | | - | |
253 | | - | |
254 | | - | |
255 | | - | |
256 | | - | |
257 | | - | |
258 | | - | |
259 | | - | |
260 | | - | |
261 | | - | |
262 | | - | |
263 | | - | |
264 | | - | |
265 | | - | |
266 | | - | |
267 | | - | |
268 | 218 | | |
269 | 219 | | |
270 | 220 | | |
| |||
0 commit comments