Skip to content

Commit c090f08

Browse files
authored
Merge branch 'master' into kcons/remap
2 parents 32e7022 + 00d9a23 commit c090f08

File tree

1,532 files changed

+319527
-325298
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,532 files changed

+319527
-325298
lines changed

.github/workflows/backend.yml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,7 @@ jobs:
253253
runs-on: ubuntu-24.04
254254
timeout-minutes: 10
255255
steps:
256-
- # get a non-default github token so that any changes are verified by CI
257-
if: env.SECRET_ACCESS == 'true'
258-
uses: getsentry/action-github-app-token@d4b5da6c5e37703f8c3b3e43abb5705b46e159cc # v3.0.0
256+
- uses: getsentry/action-github-app-token@d4b5da6c5e37703f8c3b3e43abb5705b46e159cc # v3.0.0
259257
id: token
260258
with:
261259
app_id: ${{ vars.SENTRY_INTERNAL_APP_ID }}
@@ -265,7 +263,6 @@ jobs:
265263

266264
- name: Setup sentry env
267265
uses: ./.github/actions/setup-sentry
268-
id: setup
269266
with:
270267
mode: backend-ci
271268

@@ -274,8 +271,7 @@ jobs:
274271
python3 -m tools.api_urls_to_typescript
275272
276273
- name: Apply any file changes
277-
# note: this runs "always" or else it's skipped when pre-commit fails
278-
if: env.SECRET_ACCESS == 'true' && startsWith(github.ref, 'refs/pull') && always()
274+
if: github.ref != 'refs/heads/master' && always()
279275
uses: getsentry/action-github-commit@31f6706ca1a7b9ad6d22c1b07bf3a92eabb05632 # v2.0.0
280276
with:
281277
github-token: ${{ steps.token.outputs.token }}

AGENTS.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,22 @@ class MyPermission(SentryPermission):
319319
}
320320
```
321321

322+
### Options System
323+
324+
Sentry uses a centralized options system where all options are registered in `src/sentry/options/defaults.py` with required default values.
325+
326+
```python
327+
# CORRECT: options.get() without default - registered default is used
328+
from sentry import options
329+
330+
batch_size = options.get("deletions.group-hash-metadata.batch-size")
331+
332+
# WRONG: Redundant default value
333+
batch_size = options.get("deletions.group-hash-metadata.batch-size", 1000)
334+
```
335+
336+
**Important**: Never suggest adding a default value to `options.get()` calls. All options are registered via `register()` in `defaults.py` which requires a default value. The options system will always return the registered default if no value is set, making a second default parameter redundant and potentially inconsistent.
337+
322338
### Logging Pattern
323339

324340
```python
@@ -394,6 +410,61 @@ class MultiProducer:
394410
4. Add indexes for queries on 1M+ row tables
395411
5. Use `db_index=True` or `db_index_together`
396412

413+
#### Composite Index Strategy: Match Your Query Patterns
414+
415+
**Critical Rule**: When writing a query that filters on multiple columns simultaneously, you MUST verify that a composite index exists covering those columns in the filter order.
416+
417+
**How to Identify When You Need a Composite Index:**
418+
419+
1. **Look for Multi-Column Filters**: Any query using multiple columns in `.filter()` or `WHERE` clause
420+
2. **Check Index Coverage**: Verify the model's `Meta.indexes` includes those columns
421+
3. **Consider Query Order**: Index column order should match the most selective filters first
422+
423+
**Common Patterns Requiring Composite Indexes:**
424+
425+
```python
426+
# NEEDS COMPOSITE INDEX: Filtering on foreign_key_id AND id
427+
Model.objects.filter(
428+
foreign_key_id__in=ids, # First column
429+
id__gt=last_id # Second column
430+
)[:batch_size]
431+
# Required: Index(fields=["foreign_key", "id"])
432+
433+
# NEEDS COMPOSITE INDEX: Status + timestamp range queries
434+
Model.objects.filter(
435+
status="open", # First column
436+
created_at__gte=start # Second column
437+
)
438+
# Required: Index(fields=["status", "created_at"])
439+
440+
# NEEDS COMPOSITE INDEX: Org + project + type lookups
441+
Model.objects.filter(
442+
organization_id=org_id, # First column
443+
project_id=proj_id, # Second column
444+
type=event_type # Third column
445+
)
446+
# Required: Index(fields=["organization", "project", "type"])
447+
```
448+
449+
**How to Check if Index Exists:**
450+
451+
1. Read the model file: Check the `Meta` class for `indexes = [...]`
452+
2. Single foreign key gets auto-index, but **NOT** when combined with other filters
453+
3. If you filter on FK + another column, you need explicit composite index
454+
455+
**Red Flags to Watch For:**
456+
457+
- Query uses `column1__in=[...]` AND `column2__gt/lt/gte/lte`
458+
- Query filters on FK relationship PLUS primary key or timestamp
459+
- Pagination queries combining filters with cursor-based `id__gt`
460+
- Large IN clauses combined with range filters
461+
462+
**When in Doubt:**
463+
464+
1. Check production query performance in Sentry issues (slow query alerts)
465+
2. Run `EXPLAIN ANALYZE` on similar queries against production-sized data
466+
3. Add the composite index if table has 1M+ rows and query runs in loops/batches
467+
397468
## Anti-Patterns (NEVER DO)
398469

399470
### Backend

fixtures/github.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3012,7 +3012,27 @@
30123012
"type": "User",
30133013
"site_admin": false
30143014
},
3015-
"assignees": [],
3015+
"assignees": [
3016+
{
3017+
"login": "octocat",
3018+
"id": 1,
3019+
"avatar_url": "https://avatars.githubusercontent.com/u/1?v=3",
3020+
"gravatar_id": "",
3021+
"url": "https://api.github.com/users/octocat",
3022+
"html_url": "https://github.com/octocat",
3023+
"followers_url": "https://api.github.com/users/octocat/followers",
3024+
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
3025+
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
3026+
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
3027+
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
3028+
"organizations_url": "https://api.github.com/users/octocat/orgs",
3029+
"repos_url": "https://api.github.com/users/octocat/repos",
3030+
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
3031+
"received_events_url": "https://api.github.com/users/octocat/received_events",
3032+
"type": "User",
3033+
"site_admin": false
3034+
}
3035+
],
30163036
"milestone": null,
30173037
"comments": 0,
30183038
"created_at": "2015-05-05T23:40:28Z",

jest.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ if (
253253
* node_modules, but some packages which use ES6 syntax only NEED to be
254254
* transformed.
255255
*/
256-
const ESM_NODE_MODULES = ['screenfull', 'cbor2', 'nuqs'];
256+
const ESM_NODE_MODULES = ['screenfull', 'cbor2', 'nuqs', 'color'];
257257

258258
const config: Config.InitialOptions = {
259259
verbose: false,

migrations_lockfile.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,16 @@ preprod: 0018_add_preprod_artifact_app_icon_id_field
2727

2828
prevent: 0002_alter_integration_id_not_null
2929

30-
releases: 0002_delete_dual_written_commit_tables
30+
releases: 0003_real_delete_dual_written_commit_tables
3131

3232
replays: 0006_add_bulk_delete_job
3333

34-
sentry: 1002_group_history_prev_history_remove_db_constraint
34+
sentry: 1003_group_history_prev_history_safe_removal
3535

3636
social_auth: 0003_social_auth_json_field
3737

3838
tempest: 0001_squashed_0002_make_message_type_nullable
3939

4040
uptime: 0048_delete_uptime_status_columns
4141

42-
workflow_engine: 0094_backfill_issue_stream_detector_workflows
42+
workflow_engine: 0095_unique_detectorgroup_group

package.json

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@
6868
"@sentry-internal/rrweb": "2.40.0",
6969
"@sentry-internal/rrweb-player": "2.40.0",
7070
"@sentry-internal/rrweb-snapshot": "2.40.0",
71-
"@sentry/core": "10.20.0",
72-
"@sentry/node": "10.20.0",
73-
"@sentry/react": "10.20.0",
71+
"@sentry/core": "10.23.0",
72+
"@sentry/node": "10.23.0",
73+
"@sentry/react": "10.23.0",
7474
"@sentry/release-parser": "^1.3.1",
7575
"@sentry/status-page-list": "^0.6.1",
7676
"@sentry/toolbar": "1.0.0-beta.16",
@@ -83,7 +83,6 @@
8383
"@tanstack/react-query-devtools": "5.85.0",
8484
"@tanstack/react-query-persist-client": "5.85.0",
8585
"@tanstack/react-virtual": "^3.13.6",
86-
"@types/color": "^3.0.3",
8786
"@types/diff": "5.2.1",
8887
"@types/gtag.js": "^0.0.12",
8988
"@types/history": "^3.2.5",
@@ -110,7 +109,7 @@
110109
"buffer": "^6.0.3",
111110
"cbor2": "^1.12.0",
112111
"classnames": "2.3.1",
113-
"color": "^4.2.3",
112+
"color": "5.0.2",
114113
"compression-webpack-plugin": "11.1.0",
115114
"conduit-client": "^0.4.0",
116115
"core-js": "3.45.0",
@@ -120,7 +119,7 @@
120119
"dompurify": "3.2.5",
121120
"downsample": "1.4.0",
122121
"echarts": "6.0.0",
123-
"echarts-for-react": "3.0.4",
122+
"echarts-for-react": "3.0.5",
124123
"esbuild": "0.25.10",
125124
"focus-trap": "7.6.5",
126125
"framer-motion": "12.23.12",
@@ -190,7 +189,7 @@
190189
"@prettier/plugin-oxc": "0.0.4",
191190
"@sentry-internal/rrweb-types": "2.40.0",
192191
"@sentry/jest-environment": "6.1.0",
193-
"@sentry/profiling-node": "10.20.0",
192+
"@sentry/profiling-node": "10.23.0",
194193
"@styled/typescript-styled-plugin": "^1.0.1",
195194
"@tanstack/eslint-plugin-query": "5.83.1",
196195
"@testing-library/dom": "10.4.0",

0 commit comments

Comments
 (0)