Skip to content

Commit 6c0099e

Browse files
authored
Merge branch 'master' into ryan953/rm-nonbadges
2 parents e26d782 + 978068f commit 6c0099e

File tree

8 files changed

+52
-9
lines changed

8 files changed

+52
-9
lines changed

src/sentry/integrations/slack/tasks/send_notifications_on_activity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def activity_created_receiver(instance, created, **kwargs) -> None:
6363
"""
6464
If an activity is created for an issue, this will trigger, and we can kick off an async process
6565
"""
66-
log_params = {"activity_id": instance.id, "created": created}
66+
log_params = {"activity_id": instance.id, "activity_object_created": created}
6767
_default_logger.info("receiver for activity event", extra=log_params)
6868
if not created:
6969
_default_logger.info("instance is not created, skipping post processing", extra=log_params)

src/sentry/monitors/endpoints/base_monitor_details.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,9 @@ def delete_monitor(self, request: Request, project: Project, monitor: Monitor) -
256256
for monitor_object in monitor_objects_list:
257257
# randomize slug on monitor deletion to prevent re-creation side effects
258258
if isinstance(monitor_object, Monitor):
259-
monitor_object.update(slug=get_random_string(length=24))
259+
new_slug = get_random_string(length=24)
260+
quotas.backend.update_monitor_slug(monitor.slug, new_slug, monitor.project_id)
261+
monitor_object.update(slug=new_slug)
260262

261263
schedule = RegionScheduledDeletion.schedule(
262264
monitor_object, days=0, actor=request.user

src/sentry/replays/tasks.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
import concurrent.futures as cf
44
from typing import Any
55

6+
from google.cloud.exceptions import NotFound
7+
68
from sentry.replays.lib.kafka import initialize_replays_publisher
7-
from sentry.replays.lib.storage import filestore, storage
9+
from sentry.replays.lib.storage import filestore, make_video_filename, storage, storage_kv
810
from sentry.replays.models import ReplayRecordingSegment
911
from sentry.replays.usecases.events import archive_event
1012
from sentry.replays.usecases.reader import fetch_segments_metadata
@@ -54,15 +56,18 @@ def delete_replay_recording(project_id: int, replay_id: str) -> None:
5456
# Filestore and direct storage segments are split into two different delete operations.
5557
direct_storage_segments = []
5658
filestore_segments = []
59+
video_filenames = []
5760
for segment in segments_from_metadata:
61+
video_filenames.append(make_video_filename(segment))
5862
if segment.file_id:
5963
filestore_segments.append(segment)
6064
else:
6165
direct_storage_segments.append(segment)
6266

6367
# Issue concurrent delete requests when interacting with a remote service provider.
64-
if direct_storage_segments:
65-
with cf.ThreadPoolExecutor(max_workers=100) as pool:
68+
with cf.ThreadPoolExecutor(max_workers=100) as pool:
69+
pool.map(_delete_if_exists, video_filenames)
70+
if direct_storage_segments:
6671
pool.map(storage.delete, direct_storage_segments)
6772

6873
# This will only run if "filestore" was used to store the files. This hasn't been the
@@ -81,3 +86,11 @@ def archive_replay(publisher: KafkaPublisher, project_id: int, replay_id: str) -
8186
# We publish manually here because we sometimes provide a managed Kafka
8287
# publisher interface which has its own setup and teardown behavior.
8388
publisher.publish("ingest-replay-events", message)
89+
90+
91+
def _delete_if_exists(filename: str) -> None:
92+
"""Delete the blob if it exists or silence the 404."""
93+
try:
94+
storage_kv.delete(filename)
95+
except NotFound:
96+
pass

src/sentry/services/hybrid_cloud/import_export/impl.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import traceback
77

8+
import sentry_sdk
89
from django.core.exceptions import ValidationError as DjangoValidationError
910
from django.core.serializers import deserialize, serialize
1011
from django.core.serializers.base import DeserializationError
@@ -325,6 +326,7 @@ def import_by_model(
325326
)
326327

327328
except DeserializationError:
329+
sentry_sdk.capture_exception()
328330
return RpcImportError(
329331
kind=RpcImportErrorKind.DeserializationFailed,
330332
on=InstanceID(model_name),
@@ -349,6 +351,7 @@ def import_by_model(
349351
)
350352
return existing_import_chunk
351353
except Exception:
354+
sentry_sdk.capture_exception()
352355
return RpcImportError(
353356
kind=RpcImportErrorKind.Unknown,
354357
on=InstanceID(model_name),
@@ -358,20 +361,23 @@ def import_by_model(
358361
# All non-`ImportChunk`-related kinds of `IntegrityError` mean that the user's data was
359362
# not properly sanitized against collision. This could be the fault of either the import
360363
# logic, or the user's data itself.
364+
sentry_sdk.capture_exception()
361365
return RpcImportError(
362366
kind=RpcImportErrorKind.IntegrityError,
363367
on=InstanceID(model_name),
364368
reason=str(e),
365369
)
366370

367371
except DatabaseError as e:
372+
sentry_sdk.capture_exception()
368373
return RpcImportError(
369374
kind=RpcImportErrorKind.DatabaseError,
370375
on=InstanceID(model_name),
371376
reason=str(e),
372377
)
373378

374379
except Exception:
380+
sentry_sdk.capture_exception()
375381
return RpcImportError(
376382
kind=RpcImportErrorKind.Unknown,
377383
on=InstanceID(model_name),
@@ -509,6 +515,7 @@ def yield_objects():
509515
)
510516

511517
except Exception:
518+
sentry_sdk.capture_exception()
512519
return RpcExportError(
513520
kind=RpcExportErrorKind.Unknown,
514521
on=InstanceID(model_name),

static/app/utils/useUrlParams.spec.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ import useUrlParams from './useUrlParams';
88
jest.mock('react-router');
99
jest.mock('sentry/utils/useLocation');
1010

11-
type Query = {limit: string; page: string};
11+
type Query = {array: string[]; limit: string; page: string};
1212

1313
describe('useUrlParams', () => {
1414
beforeEach(() => {
1515
jest.mocked(browserHistory.getCurrentLocation).mockReturnValue({
1616
query: {
1717
page: '3',
1818
limit: '50',
19+
array: ['first', 'second'],
1920
},
2021
} as Location<Query>);
2122
});
@@ -25,6 +26,7 @@ describe('useUrlParams', () => {
2526

2627
expect(result.current.getParamValue('page')).toBe('3');
2728
expect(result.current.getParamValue('limit')).toBe('50');
29+
expect(result.current.getParamValue('array')).toBe('first');
2830
expect(result.current.getParamValue('foo')).toBeUndefined();
2931
});
3032

@@ -54,6 +56,7 @@ describe('useUrlParams', () => {
5456

5557
expect(browserHistory.push).toHaveBeenCalledWith({
5658
query: {
59+
array: ['first', 'second'],
5760
page: '4',
5861
limit: '50',
5962
},
@@ -69,6 +72,7 @@ describe('useUrlParams', () => {
6972

7073
expect(browserHistory.push).toHaveBeenCalledWith({
7174
query: {
75+
array: ['first', 'second'],
7276
page: '4',
7377
limit: '50',
7478
},

static/app/utils/useUrlParams.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ function useUrlParams(defaultKey?: string, defaultValue?: string) {
2020
const getParamValue = useCallback(
2121
(key: string) => {
2222
const location = browserHistory.getCurrentLocation();
23-
return location.query[key] ?? defaultValue;
23+
// location.query.key can return string[] but we expect a singular value from this function, so we return the first string (this is picked arbitrarily) if it's string[]
24+
return Array.isArray(location.query[key])
25+
? location.query[key]?.at(0) ?? defaultValue
26+
: location.query[key] ?? defaultValue;
2427
},
2528
[defaultValue]
2629
);

tests/sentry/monitors/endpoints/test_base_monitor_details.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,8 @@ def setUp(self):
857857
self.login_as(user=self.user)
858858
super().setUp()
859859

860-
def test_simple(self):
860+
@patch("sentry.quotas.backend.update_monitor_slug")
861+
def test_simple(self, update_monitor_slug):
861862
monitor = self._create_monitor()
862863
old_slug = monitor.slug
863864

@@ -872,6 +873,7 @@ def test_simple(self):
872873
assert RegionScheduledDeletion.objects.filter(
873874
object_id=monitor.id, model_name="Monitor"
874875
).exists()
876+
update_monitor_slug.assert_called_once()
875877

876878
def test_mismatched_org_slugs(self):
877879
monitor = self._create_monitor()

tests/sentry/replays/test_project_replay_details.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77

88
from sentry.models.files.file import File
99
from sentry.replays.lib import kafka
10-
from sentry.replays.lib.storage import RecordingSegmentStorageMeta, storage
10+
from sentry.replays.lib.storage import (
11+
RecordingSegmentStorageMeta,
12+
make_video_filename,
13+
storage,
14+
storage_kv,
15+
)
1116
from sentry.replays.models import ReplayRecordingSegment
1217
from sentry.replays.testutils import assert_expected_response, mock_expected_response, mock_replay
1318
from sentry.testutils.cases import APITestCase, ReplaysSnubaTestCase
@@ -210,6 +215,7 @@ def test_delete_replay_from_clickhouse_data(self):
210215
file_id=None,
211216
)
212217
storage.set(metadata1, b"hello, world!")
218+
storage_kv.set(make_video_filename(metadata1), b"hello, world!")
213219

214220
metadata2 = RecordingSegmentStorageMeta(
215221
project_id=self.project.id,
@@ -219,6 +225,8 @@ def test_delete_replay_from_clickhouse_data(self):
219225
file_id=None,
220226
)
221227
storage.set(metadata2, b"hello, world!")
228+
# Intentionally not written.
229+
# storage_kv.set(make_video_filename(metadata2), b"hello, world!")
222230

223231
metadata3 = RecordingSegmentStorageMeta(
224232
project_id=self.project.id,
@@ -228,6 +236,7 @@ def test_delete_replay_from_clickhouse_data(self):
228236
file_id=None,
229237
)
230238
storage.set(metadata3, b"hello, world!")
239+
storage_kv.set(make_video_filename(metadata3), b"hello, world!")
231240

232241
with self.feature(REPLAYS_FEATURES):
233242
with TaskRunner():
@@ -237,3 +246,6 @@ def test_delete_replay_from_clickhouse_data(self):
237246
assert storage.get(metadata1) is None
238247
assert storage.get(metadata2) is None
239248
assert storage.get(metadata3) is not None
249+
assert storage_kv.get(make_video_filename(metadata1)) is None
250+
assert storage_kv.get(make_video_filename(metadata2)) is None
251+
assert storage_kv.get(make_video_filename(metadata3)) is not None

0 commit comments

Comments
 (0)