1
1
from __future__ import annotations
2
2
3
- import atexit
4
3
import functools
5
4
import logging
6
5
from abc import ABCMeta , abstractmethod
7
6
from collections import defaultdict
8
7
from collections .abc import Callable , Mapping , Sequence
9
- from concurrent .futures import ThreadPoolExecutor
10
8
from datetime import datetime , timedelta
11
9
from typing import Any
12
10
13
11
from django .db .models import Q
14
12
from django .utils import timezone
15
13
from django .utils .functional import SimpleLazyObject
16
14
17
- from sentry import features , quotas
15
+ from sentry import quotas
18
16
from sentry .api .event_search import SearchFilter
19
17
from sentry .db .models .manager .base_query_set import BaseQuerySet
20
18
from sentry .exceptions import InvalidSearchQuery
33
31
from sentry .search .base import SearchBackend
34
32
from sentry .search .events .constants import EQUALITY_OPERATORS , OPERATOR_TO_DJANGO
35
33
from sentry .search .snuba .executors import (
36
- POSTGRES_ONLY_SEARCH_FIELDS ,
37
34
AbstractQueryExecutor ,
38
- InvalidQueryForExecutor ,
39
35
PostgresSnubaQueryExecutor ,
40
36
TrendsSortWeights ,
41
37
)
@@ -286,147 +282,6 @@ def seer_actionability_filter(trigger_values: list[float]) -> Q:
286
282
return query
287
283
288
284
289
- _side_query_pool = ThreadPoolExecutor (max_workers = 10 )
290
-
291
- atexit .register (_side_query_pool .shutdown , False )
292
-
293
-
294
- def _group_attributes_side_query (
295
- events_only_search_results : CursorResult [Group ],
296
- builder : Callable [[], BaseQuerySet [Group , Group ]],
297
- projects : Sequence [Project ],
298
- retention_window_start : datetime | None ,
299
- group_queryset : BaseQuerySet [Group , Group ],
300
- environments : Sequence [Environment ] | None = None ,
301
- sort_by : str = "date" ,
302
- limit : int = 100 ,
303
- cursor : Cursor | None = None ,
304
- count_hits : bool = False ,
305
- paginator_options : Mapping [str , Any ] | None = None ,
306
- search_filters : Sequence [SearchFilter ] | None = None ,
307
- date_from : datetime | None = None ,
308
- date_to : datetime | None = None ,
309
- max_hits : int | None = None ,
310
- referrer : str | None = None ,
311
- actor : Any | None = None ,
312
- aggregate_kwargs : TrendsSortWeights | None = None ,
313
- ) -> None :
314
- def __run_joined_query_and_log_metric (
315
- events_only_search_results : CursorResult [Group ],
316
- builder : Callable [[], BaseQuerySet [Group , Group ]],
317
- projects : Sequence [Project ],
318
- retention_window_start : datetime | None ,
319
- group_queryset : BaseQuerySet [Group , Group ],
320
- environments : Sequence [Environment ] | None = None ,
321
- sort_by : str = "date" ,
322
- limit : int = 100 ,
323
- cursor : Cursor | None = None ,
324
- count_hits : bool = False ,
325
- paginator_options : Mapping [str , Any ] | None = None ,
326
- search_filters : Sequence [SearchFilter ] | None = None ,
327
- date_from : datetime | None = None ,
328
- date_to : datetime | None = None ,
329
- max_hits : int | None = None ,
330
- referrer : str | None = None ,
331
- actor : Any | None = None ,
332
- aggregate_kwargs : TrendsSortWeights | None = None ,
333
- ) -> None :
334
- from sentry .utils import metrics
335
-
336
- try :
337
- from sentry .search .snuba .executors import GroupAttributesPostgresSnubaQueryExecutor
338
-
339
- executor = GroupAttributesPostgresSnubaQueryExecutor ()
340
- with metrics .timer ("snuba.search.group_attributes_joined.duration" ):
341
- cursor_results = executor .query (
342
- projects ,
343
- retention_window_start ,
344
- builder (),
345
- environments ,
346
- sort_by ,
347
- limit ,
348
- cursor ,
349
- count_hits ,
350
- paginator_options ,
351
- search_filters ,
352
- date_from ,
353
- date_to ,
354
- max_hits ,
355
- referrer ,
356
- actor ,
357
- aggregate_kwargs ,
358
- )
359
- joined_hits = len (cursor_results .results )
360
- events_only_search_hits = len (events_only_search_results .results )
361
- if events_only_search_hits > 0 :
362
- if joined_hits == events_only_search_hits :
363
- comparison = "equal"
364
- elif joined_hits > events_only_search_hits :
365
- comparison = "greater"
366
- else :
367
- # the joined query shouldn't have fewer hits since the query is deliberately less restrictive
368
- comparison = "less"
369
-
370
- metrics .incr (
371
- "snuba.search.group_attributes_joined.events_compared" ,
372
- tags = {"comparison" : comparison },
373
- )
374
-
375
- metrics .incr ("snuba.search.group_attributes_joined.query" , tags = {"exception" : "none" })
376
- except InvalidQueryForExecutor as e :
377
- logger .info (
378
- "unsupported query received in GroupAttributesPostgresSnubaQueryExecutor" ,
379
- exc_info = True ,
380
- )
381
- metrics .incr (
382
- "snuba.search.group_attributes_joined.query" ,
383
- tags = {
384
- "exception" : f"{ type (e ).__module__ } .{ type (e ).__qualname__ } " ,
385
- },
386
- )
387
- except Exception as e :
388
- logger .warning (
389
- "failed to load side query from _group_attributes_side_query" , exc_info = True
390
- )
391
- metrics .incr (
392
- "snuba.search.group_attributes_joined.query" ,
393
- tags = {
394
- "exception" : f"{ type (e ).__module__ } .{ type (e ).__qualname__ } " ,
395
- },
396
- )
397
- finally :
398
- # since this code is running in a thread and django establishes a connection per thread, we need to
399
- # explicitly close the connection assigned to this thread to avoid linger connections
400
- from django .db import connection
401
-
402
- connection .close ()
403
-
404
- try :
405
- _side_query_pool .submit (
406
- __run_joined_query_and_log_metric ,
407
- events_only_search_results ,
408
- builder ,
409
- projects ,
410
- retention_window_start ,
411
- group_queryset ,
412
- environments ,
413
- sort_by ,
414
- limit ,
415
- cursor ,
416
- count_hits ,
417
- paginator_options ,
418
- search_filters ,
419
- date_from ,
420
- date_to ,
421
- max_hits ,
422
- referrer ,
423
- actor ,
424
- aggregate_kwargs ,
425
- )
426
- except Exception :
427
- logger .exception ("failed to submit group-attributes search side-query to pool" )
428
-
429
-
430
285
class Condition :
431
286
"""\
432
287
Adds a single filter to a ``QuerySet`` object. Used with
@@ -520,7 +375,6 @@ def query(
520
375
referrer : str | None = None ,
521
376
actor : Any | None = None ,
522
377
aggregate_kwargs : TrendsSortWeights | None = None ,
523
- use_group_snuba_dataset : bool = False ,
524
378
) -> CursorResult [Group ]:
525
379
search_filters = search_filters if search_filters is not None else []
526
380
# ensure projects are from same org
@@ -537,22 +391,14 @@ def query(
537
391
else :
538
392
retention_window_start = None
539
393
540
- if use_group_snuba_dataset :
541
- # we need to handle two cases fo the group queryset:
542
- # 1. Limit results to groups that are not pending deletion or merge
543
- # 2. Handle queries snuba doesn't support such as bookmarked_by, linked, subscribed_by, etc
544
- # For the second case, we hit postgres before Snuba to get the group ids
545
- group_queryset = self ._build_limited_group_queryset (projects , search_filters )
546
-
547
- else :
548
- group_queryset = self ._build_group_queryset (
549
- projects = projects ,
550
- environments = environments ,
551
- search_filters = search_filters ,
552
- retention_window_start = retention_window_start ,
553
- date_from = date_from ,
554
- date_to = date_to ,
555
- )
394
+ group_queryset = self ._build_group_queryset (
395
+ projects = projects ,
396
+ environments = environments ,
397
+ search_filters = search_filters ,
398
+ retention_window_start = retention_window_start ,
399
+ date_from = date_from ,
400
+ date_to = date_to ,
401
+ )
556
402
557
403
query_executor = self ._get_query_executor (
558
404
group_queryset = group_queryset ,
@@ -561,7 +407,6 @@ def query(
561
407
search_filters = search_filters ,
562
408
date_from = date_from ,
563
409
date_to = date_to ,
564
- use_group_snuba_dataset = use_group_snuba_dataset ,
565
410
)
566
411
567
412
# ensure sort strategy is supported by executor
@@ -588,69 +433,8 @@ def query(
588
433
aggregate_kwargs = aggregate_kwargs ,
589
434
)
590
435
591
- if len (projects ) > 0 and features .has (
592
- "organizations:issue-search-group-attributes-side-query" , projects [0 ].organization
593
- ):
594
- new_group_queryset = self ._build_group_queryset (
595
- projects = projects ,
596
- environments = environments ,
597
- search_filters = search_filters ,
598
- retention_window_start = retention_window_start ,
599
- date_from = date_from ,
600
- date_to = date_to ,
601
- )
602
-
603
- builder = functools .partial (
604
- self ._build_group_queryset ,
605
- projects = projects ,
606
- environments = environments ,
607
- search_filters = search_filters ,
608
- retention_window_start = retention_window_start ,
609
- date_from = date_from ,
610
- date_to = date_to ,
611
- )
612
-
613
- _group_attributes_side_query (
614
- events_only_search_results = query_results ,
615
- builder = builder ,
616
- projects = projects ,
617
- retention_window_start = retention_window_start ,
618
- group_queryset = new_group_queryset ,
619
- environments = environments ,
620
- sort_by = sort_by ,
621
- limit = limit ,
622
- cursor = cursor ,
623
- count_hits = count_hits ,
624
- paginator_options = paginator_options ,
625
- search_filters = search_filters ,
626
- date_from = date_from ,
627
- date_to = date_to ,
628
- max_hits = max_hits ,
629
- referrer = referrer ,
630
- actor = actor ,
631
- aggregate_kwargs = aggregate_kwargs ,
632
- )
633
-
634
436
return query_results
635
437
636
- def _build_limited_group_queryset (
637
- self , projects : Sequence [Project ], search_filters : Sequence [SearchFilter ]
638
- ) -> BaseQuerySet [Group , Group ]:
639
- """
640
- Builds a group queryset to handle joins for data that doesn't exist in Clickhouse on the group_attributes dataset
641
- """
642
- # Filter search_filters to only include 'bookmarked_by', 'linked', 'subscribed_by'
643
- filtered_search_filters = [
644
- sf for sf in search_filters if sf .key .name in POSTGRES_ONLY_SEARCH_FIELDS
645
- ]
646
- # Use the filtered search filters for further processing
647
- return self ._build_group_queryset (
648
- projects = projects ,
649
- environments = None ,
650
- search_filters = filtered_search_filters ,
651
- retention_window_start = None ,
652
- )
653
-
654
438
def _build_group_queryset (
655
439
self ,
656
440
projects : Sequence [Project ],
@@ -721,7 +505,6 @@ def _get_query_executor(
721
505
search_filters : Sequence [SearchFilter ],
722
506
date_from : datetime | None ,
723
507
date_to : datetime | None ,
724
- use_group_snuba_dataset : bool ,
725
508
) -> AbstractQueryExecutor :
726
509
"""This method should return an implementation of the AbstractQueryExecutor
727
510
We will end up calling .query() on the class returned by this method"""
@@ -730,10 +513,6 @@ def _get_query_executor(
730
513
731
514
class EventsDatasetSnubaSearchBackend (SnubaSearchBackendBase ):
732
515
def _get_query_executor (self , * args : Any , ** kwargs : Any ) -> AbstractQueryExecutor :
733
- if kwargs .get ("use_group_snuba_dataset" ):
734
- from sentry .search .snuba .executors import GroupAttributesPostgresSnubaQueryExecutor
735
-
736
- return GroupAttributesPostgresSnubaQueryExecutor ()
737
516
return PostgresSnubaQueryExecutor ()
738
517
739
518
def _get_queryset_conditions (
0 commit comments