Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
a22692b
ref(cmdk) refactor state to a reducer (#111505)
JonasBa Mar 25, 2026
2e26946
fix(performance): Bring back user column on segment span tables (#111…
mjq Mar 25, 2026
10b8ca7
bug(snapshots): Fix snapshot grouping (#111527)
rbro112 Mar 25, 2026
6a63522
chore(tasks): remove seer task shims after getsentry migration (#111463)
cvxluo Mar 25, 2026
a49fd27
fix(seer): render explorer panel when page-frame feature is enabled (…
JonasBa Mar 25, 2026
b674a6a
fix(issues): Move coverage legend above stack trace (#111494)
scttcper Mar 25, 2026
c53a55d
fix(search-query-builder): Remove AND/OR suggestions when logical ope…
malwilley Mar 25, 2026
7e509b5
Revert "ref: Migrate remaining ThreadPoolExecutor usages and enable S…
getsentry-bot Mar 25, 2026
bea5eed
fix(spans): Exclude segment span from breakdown computation (#111520)
mjq Mar 25, 2026
e0588ce
feat(integrations): Add lightweight RPC method to fetch org IDs by pr…
Mihir-Mavalankar Mar 25, 2026
1222d4d
feat(scm): Show repos from other/unknown providers in the treeview co…
ryan953 Mar 25, 2026
b024fbc
chore: Add machine-learning-ai as codeowner for SeerComboBox files (#…
aliu39 Mar 25, 2026
7a5177a
fix(preprod): Use content_hash as canonical image key for deduplicati…
NicoHinderling Mar 25, 2026
2d3cf62
feat(np): Adds rough notification renderer for issue alerts, as a thi…
GabeVillalobos Mar 25, 2026
89e9416
chore: Remove graduated feature flag performance-new-widget-designs (…
wedamija Mar 25, 2026
e7ee050
feat(seer): Rename SCM seer settings tab to Repositories (#111538)
ryan953 Mar 25, 2026
f0fed62
build(deps): Add codeowners-coverage as dev dependency (#111461)
NicoHinderling Mar 25, 2026
bb53021
ref(ui): Replace framer-motion ring animation with CSS transition (#1…
evanpurkhiser Mar 25, 2026
a3d3121
ref(processing_errors): Generalize detection framework for multiple c…
wedamija Mar 25, 2026
6cd70fe
ref(scm): Move `should_increment_contributor_seat` to provider-agnost…
billyvg Mar 25, 2026
2c09095
fix(modal): Restore focus to trigger element when modal closes (#111542)
JonasBa Mar 25, 2026
f51d314
ref(workflows): Use WorkflowId directly instead of _ActionFilterCache…
kcons Mar 25, 2026
6dfa09a
test(insights): Replace useLocation/usePageFilters mocks with initial…
scttcper Mar 25, 2026
a4f82ed
ref(seer): Delete Seer settings ProjectOption rows instead of writing…
srest2021 Mar 25, 2026
6918063
chore(autofix): Update implementation plan to plan (#111530)
Zylphrex Mar 25, 2026
4d3de46
feat(preprod): Add auto-expansion of a section on arrow key navigatio…
rbro112 Mar 25, 2026
23d21c9
feat(workflows): Add periodic WorkflowFireHistory backlog clean-up ta…
kcons Mar 25, 2026
3dd956b
feat(workflows) Add a workflow engine implementation of OrganizationI…
kcons Mar 25, 2026
13212a8
feat(codeowners): Allow a dirty baseline file as long as code has COD…
Mar 25, 2026
b8083cd
feat(seer): Seer SCM Overview (#111343)
ryan953 Mar 25, 2026
7f90d00
feat(nav): improve mobile navigation (#111549)
JonasBa Mar 25, 2026
0941e33
feat(context engine): Only search orgs with SCM integration for index…
Mihir-Mavalankar Mar 25, 2026
9528297
fix(footer): use `StatusIndicator` component (#111548)
natemoo-re Mar 25, 2026
cc094c8
ref(core): new slider (#111414)
natemoo-re Mar 25, 2026
5ca7389
chore(autofix): Add flag for seer-issues-view (#111526)
Zylphrex Mar 25, 2026
3df942b
fix(cache): Ensure per-thread pymemcache clients in ReconnectingMemca…
gricha Mar 25, 2026
b2dfa04
fix(issues): Add stack trace column gap between coverage border and s…
scttcper Mar 25, 2026
318f192
ci(snapshots): Update sentry-cli to 3.3.4-snapshot build (#111560)
NicoHinderling Mar 25, 2026
74aee8c
ref(modals) update animation (#111559)
JonasBa Mar 25, 2026
01f5445
chore(ACI): Add error to response if multiple if/then blocks used in …
ceorourke Mar 25, 2026
06032d1
fix(seer): Fix a typo, no dash (#111558)
ryan953 Mar 25, 2026
7963a78
feat(cells): Cell architecture and migration skill (#111563)
lynnagara Mar 25, 2026
9eefb2e
chore(ci): Add configurable timeout to setup-sentry composite action …
kenzoengineer Mar 25, 2026
6fd622e
ref(cmdk) fix list gap (#111541)
JonasBa Mar 25, 2026
8e90e82
ref(codeowners) add design eng as codeowners (#111564)
JonasBa Mar 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
267 changes: 267 additions & 0 deletions .agents/skills/cell-architecture/SKILL.md

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
/bin/mock* @getsentry/app-backend
/src/sentry/data/samples/ @getsentry/app-backend
/src/sentry/cache/ @getsentry/app-backend
/tests/sentry/cache/ @getsentry/app-backend
/src/sentry/conf/ @getsentry/app-backend
/src/sentry/db/models/ @getsentry/app-backend
/src/sentry/models/ @getsentry/app-backend
Expand Down Expand Up @@ -330,6 +331,8 @@ tests/sentry/api/endpoints/test_organization_attribute_mappings.py @get
/tests/sentry/api/endpoints/test_organization_traces.py @getsentry/explore

/static/app/views/explore/ @getsentry/explore
/static/app/views/explore/logs/logsTabSeerComboBox.tsx @getsentry/explore @getsentry/machine-learning-ai
/static/app/views/explore/spans/spansTabSeerComboBox.tsx @getsentry/explore @getsentry/machine-learning-ai
/static/app/views/traces/ @getsentry/explore
/static/app/components/quickTrace/ @getsentry/explore
/src/sentry/insights/ @getsentry/data-browsing
Expand All @@ -339,6 +342,7 @@ tests/sentry/api/endpoints/test_organization_attribute_mappings.py @get
/static/app/components/events/interfaces/spans/ @getsentry/data-browsing
/static/app/components/events/viewHierarchy/* @getsentry/data-browsing
/static/app/components/searchQueryBuilder/ @getsentry/data-browsing
/static/app/components/searchQueryBuilder/askSeerCombobox/ @getsentry/data-browsing @getsentry/machine-learning-ai
/static/app/components/arithmeticBuilder/ @getsentry/data-browsing

/static/app/components/charts/ @getsentry/data-browsing
Expand All @@ -349,6 +353,7 @@ tests/sentry/api/endpoints/test_organization_attribute_mappings.py @get
/static/app/components/modals/widgetViewerModal* @getsentry/dashboards

/static/app/views/discover/ @getsentry/explore
/static/app/views/discover/results/issueListSeerComboBox.tsx @getsentry/explore @getsentry/machine-learning-ai
/static/app/utils/discover/ @getsentry/explore
/static/app/utils/timeSeries/ @getsentry/data-browsing
## Endof Visibility
Expand Down Expand Up @@ -475,6 +480,7 @@ tests/sentry/api/endpoints/test_organization_attribute_mappings.py @get

/tests/sentry_plugins/ @getsentry/ecosystem
/tests/sentry/integrations/ @getsentry/ecosystem
/tests/sentry/notifications/ @getsentry/alerts-notifications @getsentry/ecosystem

# To find matching files -> find . -name "*sentry_app*.py"
*sentry_app*.py @getsentry/product-owners-settings-integrations @getsentry/ecosystem
Expand Down Expand Up @@ -663,6 +669,7 @@ tests/sentry/api/endpoints/test_organization_attribute_mappings.py @get
/static/app/components/issues/ @getsentry/issue-workflow
/static/app/components/stackTrace/ @getsentry/issue-workflow
/static/app/views/issueList/ @getsentry/issue-workflow
/static/app/views/issueList/issueListSeerComboBox.tsx @getsentry/issue-workflow @getsentry/machine-learning-ai
/static/app/views/issueList/pages/supergroups.tsx @getsentry/issue-detection-frontend
/static/app/views/issueList/supergroups/ @getsentry/issue-detection-frontend
/static/app/views/issueDetails/ @getsentry/issue-workflow
Expand Down Expand Up @@ -798,6 +805,7 @@ tests/sentry/api/endpoints/test_organization_attribute_mappings.py @get
/static/app/views/settings/ @getsentry/design-engineering
/static/app/views/nav/ @getsentry/design-engineering
/static/app/bootstrap/ @getsentry/design-engineering
/static/app/components/commandPalette/ @getsentry/design-engineering
# Config files
/figma.config.json @getsentry/design-engineering
/knip.config.ts @getsentry/design-engineering
Expand Down Expand Up @@ -856,6 +864,10 @@ tests/sentry/api/endpoints/test_organization_attribute_mappings.py @get
/tests/sentry/conduit/ @getsentry/sre-infrastructure-engineering
# End of Conduit

# Cell architecture
/.agents/skills/cell-architecture @getsentry/sre-infrastructure-engineering
# End of cell architecture

# Foundational Storage
/src/sentry/objectstore/ @getsentry/foundational-storage
/tests/sentry/objectstore/ @getsentry/foundational-storage
Expand Down
8 changes: 7 additions & 1 deletion .github/actions/setup-sentry/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ inputs:
description: 'Skip bringing up devservices'
required: false
default: 'false'
devservices-timeout-minutes:
description: 'Maximum minutes for devservices up'
required: false
default: '10'

outputs:
matrix-instance-number:
Expand Down Expand Up @@ -131,13 +135,15 @@ runs:
env:
WORKDIR: ${{ inputs.workdir }}
ENABLE_AUTORUN_MIGRATION_SEARCH_ISSUES: '1'
DEVSERVICES_TIMEOUT: ${{ inputs.devservices-timeout-minutes }}
DEVSERVICES_MODE: ${{ inputs.mode }}
run: |
sentry init

# This is necessary to bring up devservices with appropriate sentry config
cd "$WORKDIR"

devservices up --mode ${{ inputs.mode }}
timeout "${DEVSERVICES_TIMEOUT}m" devservices up --mode "$DEVSERVICES_MODE"

# have tests listen on the docker gateway ip so loopback can occur
echo "DJANGO_LIVE_TEST_SERVER_ADDRESS=$(docker network inspect bridge --format='{{(index .IPAM.Config 0).Gateway}}')" >> "$GITHUB_ENV"
Expand Down
66 changes: 0 additions & 66 deletions .github/codeowners-coverage-baseline.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2246,72 +2246,6 @@ tests/sentry/new_migrations/monkey/test_monkey.py
tests/sentry/newsletter/__init__.py
tests/sentry/newsletter/test_base.py
tests/sentry/newsletter/test_dummy.py
tests/sentry/notifications/__init__.py
tests/sentry/notifications/api/endpoints/__init__.py
tests/sentry/notifications/api/endpoints/test_notification_actions_available.py
tests/sentry/notifications/api/endpoints/test_notification_actions_details.py
tests/sentry/notifications/api/endpoints/test_notification_actions_index.py
tests/sentry/notifications/api/endpoints/test_notification_defaults.py
tests/sentry/notifications/api/endpoints/test_user_notification_details.py
tests/sentry/notifications/api/endpoints/test_user_notification_email.py
tests/sentry/notifications/api/endpoints/test_user_notification_settings_options.py
tests/sentry/notifications/api/endpoints/test_user_notification_settings_options_details.py
tests/sentry/notifications/api/endpoints/test_user_notification_settings_providers.py
tests/sentry/notifications/models/test_notificationaction.py
tests/sentry/notifications/models/test_notificationsettingoption.py
tests/sentry/notifications/models/test_notificationsettingprovider.py
tests/sentry/notifications/notification_action/__init__.py
tests/sentry/notifications/notification_action/metric_alert_registry/__init__.py
tests/sentry/notifications/notification_action/metric_alert_registry/test_discord_metric_alert_handler.py
tests/sentry/notifications/notification_action/metric_alert_registry/test_email_metric_alert_handler.py
tests/sentry/notifications/notification_action/metric_alert_registry/test_msteams_metric_alert_handler.py
tests/sentry/notifications/notification_action/metric_alert_registry/test_opsgenie_metric_alert_handler.py
tests/sentry/notifications/notification_action/metric_alert_registry/test_pagerduty_metric_alert_handler.py
tests/sentry/notifications/notification_action/metric_alert_registry/test_slack_metric_alert_handler.py
tests/sentry/notifications/notification_action/test_group_type_notification_registry_handlers.py
tests/sentry/notifications/notification_action/test_grouptype.py
tests/sentry/notifications/notification_action/test_issue_alert_registry_handlers.py
tests/sentry/notifications/notification_action/test_metric_alert_registry_handlers.py
tests/sentry/notifications/notifications/__init__.py
tests/sentry/notifications/notifications/organization_request/test_integration_request.py
tests/sentry/notifications/notifications/organization_request/test_invite_request.py
tests/sentry/notifications/notifications/test_assigned.py
tests/sentry/notifications/notifications/test_digests.py
tests/sentry/notifications/notifications/test_organization_request.py
tests/sentry/notifications/notifications/test_suspect_commits_activity.py
tests/sentry/notifications/platform/__init__.py
tests/sentry/notifications/platform/api/__init__.py
tests/sentry/notifications/platform/api/endpoints/__init__.py
tests/sentry/notifications/platform/api/endpoints/test_internal_registered_templates.py
tests/sentry/notifications/platform/discord/__init__.py
tests/sentry/notifications/platform/discord/test_provider.py
tests/sentry/notifications/platform/email/__init__.py
tests/sentry/notifications/platform/email/test_provider.py
tests/sentry/notifications/platform/msteams/__init__.py
tests/sentry/notifications/platform/msteams/test_provider.py
tests/sentry/notifications/platform/slack/__init__.py
tests/sentry/notifications/platform/slack/renderers/__init__.py
tests/sentry/notifications/platform/slack/renderers/test_seer.py
tests/sentry/notifications/platform/slack/test_provider.py
tests/sentry/notifications/platform/templates/__init__.py
tests/sentry/notifications/platform/templates/test_seer.py
tests/sentry/notifications/platform/test_provider.py
tests/sentry/notifications/platform/test_registry.py
tests/sentry/notifications/platform/test_rollout.py
tests/sentry/notifications/platform/test_service.py
tests/sentry/notifications/platform/test_target.py
tests/sentry/notifications/platform/test_threading.py
tests/sentry/notifications/test_apps.py
tests/sentry/notifications/test_class_manager.py
tests/sentry/notifications/test_helpers.py
tests/sentry/notifications/test_notificationcontroller.py
tests/sentry/notifications/test_notificationmessage_table_constraints.py
tests/sentry/notifications/test_notifications.py
tests/sentry/notifications/test_utils.py
tests/sentry/notifications/utils/__init__.py
tests/sentry/notifications/utils/test_open_period.py
tests/sentry/notifications/utils/test_participants.py
tests/sentry/notifications/utils/test_tasks.py
tests/sentry/onboarding_tasks/__init__.py
tests/sentry/onboarding_tasks/backends/__init__.py
tests/sentry/onboarding_tasks/backends/test_organization_onboarding_tasks.py
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeowners-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
python-version: '3.11'

- name: Install codeowners-coverage
run: pip install codeowners-coverage==0.2.1
run: pip install codeowners-coverage==0.3.1

- name: Run CODEOWNERS coverage check
run: codeowners-coverage check
run: codeowners-coverage check --allow-dirty-baseline
2 changes: 1 addition & 1 deletion .github/workflows/frontend-snapshots.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:

- name: Install sentry-cli
if: ${{ !cancelled() }}
run: curl -sL https://sentry.io/get-cli/ | SENTRY_CLI_VERSION=3.3.3 sh
run: curl -sL https://sentry.io/get-cli/ | SENTRY_CLI_VERSION=3.3.4-snapshot.20260325.06cbbda sh

- name: Upload snapshots
id: upload
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ default = true

[dependency-groups]
dev = [
"codeowners-coverage>=0.2.1",
"codeowners-coverage>=0.3.0",
"covdefaults>=2.3.0",
"devservices>=1.2.4",
"docker>=7.1.0",
Expand Down
2 changes: 2 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ sentry =
# All other linting (E, W, F, B, LOG, I) is handled by ruff.
# See [tool.ruff] in pyproject.toml for the main linting configuration.
select = S
# S016 is temporarily disabled until the ThreadPoolExecutor migration is complete.
extend-ignore = S016
per-file-ignores =
# these scripts must have minimal dependencies so opt out of the usual sentry rules
.github/*: S
Expand Down
7 changes: 7 additions & 0 deletions src/sentry/api/serializers/models/rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,13 @@ def get_attrs(self, item_list: Sequence[Workflow], user, **kwargs):
)
serialized_actions = []
errors = []

if len(prefetched_wdcgs) > 1:
errors.append(
{
"detail": "Multiple if/then blocks are not supported in this view. Only the first if/then block is displayed."
}
)
for action in actions_with_handlers:
action_data = action_to_action_data[action]
action_data["name"] = action_to_handler[action].render_label(
Expand Down
70 changes: 48 additions & 22 deletions src/sentry/cache/backends/reconnectingmemcache.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,77 @@
import contextvars
import threading
import time
from collections.abc import Mapping
from threading import Lock
from typing import NamedTuple

import pymemcache
from django.core.cache.backends.memcached import PyMemcacheCache

from sentry.utils import metrics


class _BackendState(NamedTuple):
thread_id: int
created_at: float
client: pymemcache.Client


class ReconnectingMemcache(PyMemcacheCache):
"""
A django cache adapter adds periodic reconnecting
to PyMemcacheCache.

Periodically this adapter will close and reconnect the underlying
cache adapter to help even out load on Twemproxy.

Each thread gets its own pymemcache client instance. This is
necessary because pymemcache's HashClient is not thread-safe for
concurrent access (e.g. the _retry_dead method races on a shared
dict). Cross-thread sharing can happen when contextvars are
copied via copy_context(), since Django's CacheHandler stores
connections in a contextvar. We detect this by checking the
thread ID and creating a fresh client when a copied context is
accessed from a different thread.
"""

_class: pymemcache.Client
_options: Mapping[str, str] | None = None

def __init__(self, server, params) -> None:
self._reconnect_age: int = params.get("OPTIONS", {}).pop("reconnect_age", 300)
self._last_reconnect_at: float = time.time()
self._backend: pymemcache.Client | None = None
self._backend_lock = Lock()
self._backend_var: contextvars.ContextVar[_BackendState | None] = contextvars.ContextVar(
f"reconnecting_memcache_{id(self)}", default=None
)

super().__init__(server, params)

@property
def _cache(self) -> pymemcache.Client | None:
def _cache(self) -> pymemcache.Client:
"""
Overload PyMemcacheCache._cache with periodic reconnections.
Return a per-thread pymemcache client, reconnecting periodically
to distribute load across Twemproxy instances.
"""
age = time.time() - self._last_reconnect_at
if not self._backend or age >= self._reconnect_age:
try:
if self._backend_lock.acquire(timeout=1.0):
# Close the underlying cache connection if we haven't done that recently.
if self._backend:
self._backend.close()
self._backend = None
metrics.incr("cache.memcache.reconnect")

self._backend = self._class(self.client_servers, **self._options)
self._last_reconnect_at = time.time()
finally:
self._backend_lock.release()

return self._backend
current_tid = threading.get_ident()
state = self._backend_var.get()

if state is not None:
# Context was copied to a different thread (e.g. via
# ContextPropagatingThreadPoolExecutor). pymemcache's
# HashClient isn't thread-safe, so create a new client.
if state.thread_id != current_tid:
state = None
elif time.time() - state.created_at >= self._reconnect_age:
state.client.close()
metrics.incr("cache.memcache.reconnect")
state = None

if state is None:
client = self._class(self.client_servers, **self._options)
state = _BackendState(
thread_id=current_tid,
created_at=time.time(),
client=client,
)
self._backend_var.set(state)

return state.client
1 change: 0 additions & 1 deletion src/sentry/conf/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -1416,7 +1416,6 @@ def custom_parameter_sort(parameter: dict) -> tuple[str, int]:
# Sentry and internal client configuration

SENTRY_EARLY_FEATURES = {
"organizations:performance-new-widget-designs": "Enable updated landing page widget designs",
"organizations:profiling-global-suspect-functions": "Enable global suspect functions in profiling",
}

Expand Down
4 changes: 2 additions & 2 deletions src/sentry/features/temporary.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,6 @@ def register_temporary_features(manager: FeatureManager) -> None:
manager.add("organizations:performance-mep-bannerless-ui", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Re-enable histograms for Metrics Enhanced Performance Views
manager.add("organizations:performance-mep-reintroduce-histograms", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable updated landing page widget designs
manager.add("organizations:performance-new-widget-designs", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable MongoDB support for the Queries module
manager.add("organizations:performance-queries-mongodb-extraction", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable removing the fallback for metrics compatibility
Expand Down Expand Up @@ -296,6 +294,8 @@ def register_temporary_features(manager: FeatureManager) -> None:
manager.add("organizations:seer-overview", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable the Seer Wizard and related prompts/links/banners
manager.add("organizations:seer-wizard", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable the Seer issues view
manager.add("organizations:seer-issue-view", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable Autofix to use Seer Explorer instead of legacy Celery pipeline
manager.add("organizations:autofix-on-explorer", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=True)
# Enable Autofix to use Seer Explorer V2 designs
Expand Down
Loading
Loading