sentry-arroyo 2.20.8__py3-none-any.whl → 2.20.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -425,9 +425,7 @@ class StreamProcessor(Generic[TStrategyPayload]):
425
425
  if self.__message is not None:
426
426
  try:
427
427
  start_submit = time.time()
428
- message = (
429
- Message(self.__message) if self.__message is not None else None
430
- )
428
+ message = Message(self.__message)
431
429
  self.__processing_strategy.submit(message)
432
430
 
433
431
  self.__metrics_buffer.incr_timing(
@@ -483,6 +481,11 @@ class StreamProcessor(Generic[TStrategyPayload]):
483
481
  except InvalidMessage as e:
484
482
  self._handle_invalid_message(e)
485
483
 
484
+ if self.__is_paused:
485
+ self.__metrics_buffer.incr_counter("arroyo.consumer.resume", 1)
486
+ self.__consumer.resume([*self.__consumer.tell().keys()])
487
+ self.__is_paused = False
488
+
486
489
  else:
487
490
  # Resume if we are currently in a paused state
488
491
  if self.__is_paused:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sentry-arroyo
3
- Version: 2.20.8
3
+ Version: 2.20.10
4
4
  Summary: Arroyo is a Python library for working with streaming data.
5
5
  Home-page: https://github.com/getsentry/arroyo
6
6
  Author: Sentry
@@ -16,7 +16,7 @@ arroyo/backends/local/storages/__init__.py,sha256=AGYujdAAcn3osoj9jq84IzTywYbkID
16
16
  arroyo/backends/local/storages/abstract.py,sha256=1qVQp6roxHkK6XT2aklZyZk1qq7RzcPN6Db_CA5--kg,2901
17
17
  arroyo/backends/local/storages/memory.py,sha256=AoKDsVZzBXkOJyWArKWp3vfGfU9xLlKFXE9gsJiMIzQ,2613
18
18
  arroyo/processing/__init__.py,sha256=vZVg0wJvJfoVzlzGvnL59bT6YNIRJNQ5t7oU045Qbk4,87
19
- arroyo/processing/processor.py,sha256=mfPyqG0ZvBiucN_c2jfaYP8YjygXV2HXfHWfx4TpRi8,20426
19
+ arroyo/processing/processor.py,sha256=N5b3Nv_PIH_wnxb_5DOOd7NQTbq4Kyh6K1D9-sD5GF0,20598
20
20
  arroyo/processing/strategies/__init__.py,sha256=EU_JMb54eOxMxaC5mIFpI-sAF-X2ZScbE8czBZ7bQkY,1106
21
21
  arroyo/processing/strategies/abstract.py,sha256=nu7juEz_aQmQIH35Z8u--FBuLjkK8_LQ1hIG2xpw9AA,4808
22
22
  arroyo/processing/strategies/batching.py,sha256=s89xC6lQpBseEaApu1iNTipXGKeO95OMwinj2VBKn9s,4778
@@ -46,14 +46,14 @@ examples/transform_and_produce/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
46
46
  examples/transform_and_produce/batched.py,sha256=st2R6qTneAtV0JFbKP30Ti3sJDYj8Jkbmta9JckKdZU,2636
47
47
  examples/transform_and_produce/script.py,sha256=8kSMIjQNqGYEVyE0PvrfJh-a_UYCrJSstTp_De7kyyg,2306
48
48
  examples/transform_and_produce/simple.py,sha256=H7xqxItjl4tx34wVW5dy6mB9G39QucAtxkJSBzVmjgA,1637
49
- sentry_arroyo-2.20.8.dist-info/licenses/LICENSE,sha256=0Ng3MFdEcnz0sVD1XvGBBzbavvNp_7OAM5yVObB46jU,10829
49
+ sentry_arroyo-2.20.10.dist-info/licenses/LICENSE,sha256=0Ng3MFdEcnz0sVD1XvGBBzbavvNp_7OAM5yVObB46jU,10829
50
50
  tests/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
51
  tests/backends/mixins.py,sha256=sfNyE0VTeiD3GHOnBYl-9urvPuURI2G1BWke0cz7Dvc,20445
52
52
  tests/backends/test_commit.py,sha256=iTHfK1qsBxim0XwxgMvNNSMqDUMEHoYkYBDcgxGBFbs,831
53
53
  tests/backends/test_kafka.py,sha256=XGljy72Juesc1qbVs0D02OJitFnry72fRWQdbTqmBp4,12371
54
54
  tests/backends/test_local.py,sha256=Mfd4DFuWVSVtl1GomQ6TIoWuJNcAliKqKU0BShPlEMY,3363
55
55
  tests/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
- tests/processing/test_processor.py,sha256=PDCrmhWAt_wZKwYlBzDuEGsd8PnjKM-p4ySaPvVd11k,20781
56
+ tests/processing/test_processor.py,sha256=2uQcbNeiyuPUlpThq9KTBs_fz5JY-BqZE5Fz4Dxspl0,23274
57
57
  tests/processing/strategies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
58
  tests/processing/strategies/test_all.py,sha256=ahAF-nbdmqVkYGNCg0OFCD6fzNTA-XxYrW8NQHajCDU,10167
59
59
  tests/processing/strategies/test_batching.py,sha256=nyyX0y6qYHX7jT4gCgsUjT5RzBMDrBp790SCmOizQ0Q,11787
@@ -72,7 +72,7 @@ tests/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
72
  tests/utils/test_concurrent.py,sha256=Gwdzym2UZ1HO3rhOSGmzxImWcLFygY8P7MXHT3Q0xTE,455
73
73
  tests/utils/test_metrics.py,sha256=bI0EtGgPokMQyEqX58i0-8zvLfxRP2nWaWr2wLMaJ_o,917
74
74
  tests/utils/test_retries.py,sha256=AxJLkXWeL9AjHv_p1n0pe8CXXJp24ZQIuYBHfNcmiz4,3075
75
- sentry_arroyo-2.20.8.dist-info/METADATA,sha256=Tfi9HVQkH631_WJQGu-PjVUNjmljc9LLuuN_2rBFT8Q,2200
76
- sentry_arroyo-2.20.8.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
77
- sentry_arroyo-2.20.8.dist-info/top_level.txt,sha256=DVdMZKysL_iIxm5aY0sYgZtP5ZXMg9YBaBmGQHVmDXA,22
78
- sentry_arroyo-2.20.8.dist-info/RECORD,,
75
+ sentry_arroyo-2.20.10.dist-info/METADATA,sha256=zxvIwG5Fnbol5xK6YUeGT4_R2YwQgYjHXEudCdO74mA,2201
76
+ sentry_arroyo-2.20.10.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
77
+ sentry_arroyo-2.20.10.dist-info/top_level.txt,sha256=DVdMZKysL_iIxm5aY0sYgZtP5ZXMg9YBaBmGQHVmDXA,22
78
+ sentry_arroyo-2.20.10.dist-info/RECORD,,
@@ -622,3 +622,72 @@ def test_healthcheck(tmpdir: py.path.local) -> None:
622
622
 
623
623
  processor._run_once()
624
624
  assert tmpdir.join("health.txt").mtime() == health_mtime
625
+
626
+
627
+ def test_processor_pause_with_invalid_message() -> None:
628
+
629
+ topic = Topic("topic")
630
+
631
+ consumer = mock.Mock()
632
+ strategy = mock.Mock()
633
+ factory = mock.Mock()
634
+ factory.create_with_partitions.return_value = strategy
635
+
636
+ processor: StreamProcessor[int] = StreamProcessor(
637
+ consumer, topic, factory, IMMEDIATE
638
+ )
639
+
640
+ # Subscribe to topic
641
+ subscribe_args, subscribe_kwargs = consumer.subscribe.call_args
642
+ assert subscribe_args[0] == [topic]
643
+
644
+ # Partition assignment
645
+ partition = Partition(topic, 0)
646
+ consumer.tell.return_value = {}
647
+ assignment_callback = subscribe_kwargs["on_assign"]
648
+ offsets = {partition: 0}
649
+ assignment_callback(offsets)
650
+
651
+ # Message that we will get from polling
652
+ message = Message(BrokerValue(0, partition, 0, datetime.now()))
653
+
654
+ # Message will be rejected
655
+ consumer.poll.return_value = message.value
656
+ strategy.submit.side_effect = MessageRejected()
657
+ with assert_changes(lambda: int(consumer.pause.call_count), 0, 1):
658
+ processor._run_once()
659
+ assert strategy.submit.call_args_list[-1] == mock.call(message)
660
+
661
+ with mock.patch("time.time", return_value=time.time() + 5):
662
+ processor._run_once() # Should pause now
663
+
664
+ # Consumer is in paused state
665
+ # The same rejected message should be carried over
666
+
667
+ # All partitions are paused
668
+ consumer.paused.return_value = set(p for p in offsets)
669
+ # Simulate a continuous backpressure state where messages are being rejected
670
+ strategy.submit.side_effect = MessageRejected()
671
+
672
+ # Simulate Kafka returning nothing since the consumer is paused
673
+ consumer.poll.return_value = None
674
+
675
+ # The next poll returns nothing, but we are still carrying over the rejected message
676
+ processor._run_once()
677
+ assert consumer.poll.return_value is None
678
+
679
+ # At this point, let's say the message carried over is invalid (e.g. it could be stale)
680
+ strategy.submit.side_effect = InvalidMessage(partition, 0, needs_commit=False)
681
+
682
+ # Handles the invalid message and unpauses the consumer
683
+ with assert_changes(lambda: int(consumer.resume.call_count), 0, 1):
684
+ processor._run_once()
685
+
686
+ # Poll for the next message from Kafka
687
+ new_message = Message(BrokerValue(0, partition, 1, datetime.now()))
688
+ consumer.poll.return_value = new_message.value
689
+ strategy.submit.return_value = None
690
+ strategy.submit.side_effect = None
691
+
692
+ processor._run_once()
693
+ assert strategy.submit.call_args_list[-1] == mock.call(new_message)