sentry-arroyo 2.30.0__tar.gz → 2.31.1__tar.gz

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.
Files changed (92) hide show
  1. {sentry_arroyo-2.30.0/sentry_arroyo.egg-info → sentry_arroyo-2.31.1}/PKG-INFO +1 -1
  2. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/backends/kafka/__init__.py +2 -1
  3. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/backends/kafka/consumer.py +57 -2
  4. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1/sentry_arroyo.egg-info}/PKG-INFO +1 -1
  5. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/sentry_arroyo.egg-info/SOURCES.txt +1 -0
  6. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/setup.py +1 -1
  7. sentry_arroyo-2.31.1/tests/backends/test_confluent_producer.py +76 -0
  8. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/LICENSE +0 -0
  9. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/MANIFEST.in +0 -0
  10. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/README.md +0 -0
  11. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/__init__.py +0 -0
  12. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/backends/__init__.py +0 -0
  13. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/backends/abstract.py +0 -0
  14. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/backends/kafka/commit.py +0 -0
  15. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/backends/kafka/configuration.py +0 -0
  16. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/backends/local/__init__.py +0 -0
  17. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/backends/local/backend.py +0 -0
  18. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/backends/local/storages/__init__.py +0 -0
  19. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/backends/local/storages/abstract.py +0 -0
  20. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/backends/local/storages/memory.py +0 -0
  21. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/commit.py +0 -0
  22. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/dlq.py +0 -0
  23. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/errors.py +0 -0
  24. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/__init__.py +0 -0
  25. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/processor.py +0 -0
  26. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/__init__.py +0 -0
  27. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/abstract.py +0 -0
  28. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/batching.py +0 -0
  29. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/buffer.py +0 -0
  30. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/commit.py +0 -0
  31. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/filter.py +0 -0
  32. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/guard.py +0 -0
  33. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/healthcheck.py +0 -0
  34. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/noop.py +0 -0
  35. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/produce.py +0 -0
  36. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/reduce.py +0 -0
  37. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/run_task.py +0 -0
  38. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/run_task_in_threads.py +0 -0
  39. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/run_task_with_multiprocessing.py +0 -0
  40. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/processing/strategies/unfold.py +0 -0
  41. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/py.typed +0 -0
  42. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/types.py +0 -0
  43. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/utils/__init__.py +0 -0
  44. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/utils/clock.py +0 -0
  45. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/utils/codecs.py +0 -0
  46. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/utils/concurrent.py +0 -0
  47. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/utils/logging.py +0 -0
  48. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/utils/metricDefs.json +0 -0
  49. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/utils/metric_defs.py +0 -0
  50. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/utils/metrics.py +0 -0
  51. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/utils/profiler.py +0 -0
  52. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/arroyo/utils/retries.py +0 -0
  53. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/examples/transform_and_produce/__init__.py +0 -0
  54. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/examples/transform_and_produce/batched.py +0 -0
  55. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/examples/transform_and_produce/script.py +0 -0
  56. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/examples/transform_and_produce/simple.py +0 -0
  57. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/requirements.txt +0 -0
  58. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/sentry_arroyo.egg-info/dependency_links.txt +0 -0
  59. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/sentry_arroyo.egg-info/not-zip-safe +0 -0
  60. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/sentry_arroyo.egg-info/requires.txt +0 -0
  61. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/sentry_arroyo.egg-info/top_level.txt +0 -0
  62. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/setup.cfg +0 -0
  63. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/backends/__init__.py +0 -0
  64. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/backends/mixins.py +0 -0
  65. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/backends/test_commit.py +0 -0
  66. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/backends/test_kafka.py +0 -0
  67. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/backends/test_kafka_producer.py +0 -0
  68. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/backends/test_local.py +0 -0
  69. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/__init__.py +0 -0
  70. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/__init__.py +0 -0
  71. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/test_all.py +0 -0
  72. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/test_batching.py +0 -0
  73. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/test_buffer.py +0 -0
  74. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/test_commit.py +0 -0
  75. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/test_filter.py +0 -0
  76. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/test_guard.py +0 -0
  77. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/test_noop.py +0 -0
  78. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/test_produce.py +0 -0
  79. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/test_reduce.py +0 -0
  80. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/test_run_task.py +0 -0
  81. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/test_run_task_in_threads.py +0 -0
  82. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/test_run_task_with_multiprocessing.py +0 -0
  83. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/strategies/test_unfold.py +0 -0
  84. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/processing/test_processor.py +0 -0
  85. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/test_commit.py +0 -0
  86. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/test_dlq.py +0 -0
  87. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/test_kip848_e2e.py +0 -0
  88. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/test_types.py +0 -0
  89. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/utils/__init__.py +0 -0
  90. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/utils/test_concurrent.py +0 -0
  91. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/utils/test_metrics.py +0 -0
  92. {sentry_arroyo-2.30.0 → sentry_arroyo-2.31.1}/tests/utils/test_retries.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sentry-arroyo
3
- Version: 2.30.0
3
+ Version: 2.31.1
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
@@ -3,12 +3,13 @@ from .configuration import (
3
3
  build_kafka_consumer_configuration,
4
4
  build_kafka_producer_configuration,
5
5
  )
6
- from .consumer import KafkaConsumer, KafkaPayload, KafkaProducer
6
+ from .consumer import ConfluentProducer, KafkaConsumer, KafkaPayload, KafkaProducer
7
7
 
8
8
  __all__ = [
9
9
  "build_kafka_configuration",
10
10
  "build_kafka_consumer_configuration",
11
11
  "build_kafka_producer_configuration",
12
+ "ConfluentProducer",
12
13
  "KafkaConsumer",
13
14
  "KafkaPayload",
14
15
  "KafkaProducer",
@@ -33,7 +33,7 @@ from confluent_kafka import (
33
33
  from confluent_kafka import Consumer as ConfluentConsumer
34
34
  from confluent_kafka import KafkaError, KafkaException
35
35
  from confluent_kafka import Message as ConfluentMessage
36
- from confluent_kafka import Producer as ConfluentProducer
36
+ from confluent_kafka import Producer as ConfluentKafkaProducer
37
37
  from confluent_kafka import TopicPartition as ConfluentTopicPartition
38
38
 
39
39
  from arroyo.backends.abstract import (
@@ -50,6 +50,7 @@ from arroyo.errors import (
50
50
  )
51
51
  from arroyo.types import BrokerValue, Partition, Topic
52
52
  from arroyo.utils.concurrent import execute
53
+ from arroyo.utils.metrics import get_metrics
53
54
  from arroyo.utils.retries import BasicRetryPolicy
54
55
 
55
56
  logger = logging.getLogger(__name__)
@@ -657,7 +658,7 @@ class KafkaProducer(Producer[KafkaPayload]):
657
658
  self, configuration: Mapping[str, Any], use_simple_futures: bool = False
658
659
  ) -> None:
659
660
  self.__configuration = configuration
660
- self.__producer = ConfluentProducer(configuration)
661
+ self.__producer = ConfluentKafkaProducer(configuration)
661
662
  self.__shutdown_requested = Event()
662
663
 
663
664
  # The worker must execute in a separate thread to ensure that callbacks
@@ -742,3 +743,57 @@ class KafkaProducer(Producer[KafkaPayload]):
742
743
  def close(self) -> Future[None]:
743
744
  self.__shutdown_requested.set()
744
745
  return self.__result
746
+
747
+
748
+ # Type alias for the delivery callback function
749
+ DeliveryCallback = Callable[[Optional[KafkaError], ConfluentMessage], None]
750
+
751
+
752
+ class ConfluentProducer(ConfluentKafkaProducer): # type: ignore[misc]
753
+ """
754
+ A thin wrapper for confluent_kafka.Producer that adds metrics reporting.
755
+ """
756
+
757
+ def __init__(self, configuration: Mapping[str, Any]) -> None:
758
+ super().__init__(configuration)
759
+ self.__metrics = get_metrics()
760
+ self.producer_name = configuration.get("client.id") or None
761
+
762
+ def __metrics_delivery_callback(
763
+ self,
764
+ error: Optional[KafkaError],
765
+ _message: ConfluentMessage,
766
+ ) -> None:
767
+ if error is not None:
768
+ status = "error"
769
+ else:
770
+ status = "success"
771
+
772
+ tags = {"status": status}
773
+ if self.producer_name:
774
+ tags["producer_name"] = self.producer_name
775
+
776
+ self.__metrics.increment(
777
+ "arroyo.producer.produce_status",
778
+ 1,
779
+ tags=tags,
780
+ )
781
+
782
+ def __delivery_callback(
783
+ self,
784
+ user_callback: Optional[DeliveryCallback],
785
+ ) -> DeliveryCallback:
786
+ def wrapped(error: Optional[KafkaError], message: ConfluentMessage) -> None:
787
+ self.__metrics_delivery_callback(error, message)
788
+ if user_callback is not None:
789
+ user_callback(error, message)
790
+
791
+ return wrapped
792
+
793
+ def produce(self, *args: Any, **kwargs: Any) -> None:
794
+ # callback and on_delivery are aliases, callback takes precedence over on_delivery
795
+ callback = kwargs.pop("callback", None)
796
+ on_delivery = kwargs.pop("on_delivery", None)
797
+ user_callback = callback or on_delivery
798
+ wrapped_callback = self.__delivery_callback(user_callback)
799
+ super().produce(*args, on_delivery=wrapped_callback, **kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sentry-arroyo
3
- Version: 2.30.0
3
+ Version: 2.31.1
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
@@ -64,6 +64,7 @@ tests/test_types.py
64
64
  tests/backends/__init__.py
65
65
  tests/backends/mixins.py
66
66
  tests/backends/test_commit.py
67
+ tests/backends/test_confluent_producer.py
67
68
  tests/backends/test_kafka.py
68
69
  tests/backends/test_kafka_producer.py
69
70
  tests/backends/test_local.py
@@ -10,7 +10,7 @@ def get_requirements() -> Sequence[str]:
10
10
 
11
11
  setup(
12
12
  name="sentry-arroyo",
13
- version="2.30.0",
13
+ version="2.31.1",
14
14
  author="Sentry",
15
15
  author_email="oss@sentry.io",
16
16
  license="Apache-2.0",
@@ -0,0 +1,76 @@
1
+ from typing import Optional
2
+ from unittest import mock
3
+
4
+ from confluent_kafka import KafkaError
5
+ from confluent_kafka import Message as ConfluentMessage
6
+ from confluent_kafka import Producer as ConfluentKafkaProducer
7
+
8
+ from arroyo.backends.kafka.consumer import ConfluentProducer
9
+ from tests.metrics import Increment, TestingMetricsBackend
10
+
11
+
12
+ class TestConfluentProducer:
13
+ """
14
+ Tests for ConfluentProducer wrapper around confluent_kafka.Producer.
15
+ """
16
+
17
+ def test_init(self) -> None:
18
+ """Test that ConfluentProducer can be instantiated"""
19
+ config = {"bootstrap.servers": "fake:9092"}
20
+ producer = ConfluentProducer(config)
21
+
22
+ assert isinstance(producer, ConfluentProducer)
23
+ assert isinstance(producer, ConfluentKafkaProducer)
24
+
25
+ def test_metrics_callback_records_success(self) -> None:
26
+ """Test that the metrics callback records success metric"""
27
+ producer = ConfluentProducer(
28
+ {"bootstrap.servers": "fake:9092", "client.id": "test-producer-name"}
29
+ )
30
+ mock_message = mock.Mock(spec=ConfluentMessage)
31
+ producer._ConfluentProducer__metrics_delivery_callback(None, mock_message)
32
+ assert (
33
+ Increment(
34
+ "arroyo.producer.produce_status",
35
+ 1,
36
+ {"status": "success", "producer_name": "test-producer-name"},
37
+ )
38
+ in TestingMetricsBackend.calls
39
+ )
40
+
41
+ def test_metrics_callback_records_error(self) -> None:
42
+ """Test that the metrics callback records error metric"""
43
+ producer = ConfluentProducer({"bootstrap.servers": "fake:9092"})
44
+ mock_error = mock.Mock(spec=KafkaError)
45
+ mock_message = mock.Mock(spec=ConfluentMessage)
46
+ producer._ConfluentProducer__metrics_delivery_callback(mock_error, mock_message)
47
+ assert (
48
+ Increment("arroyo.producer.produce_status", 1, {"status": "error"})
49
+ in TestingMetricsBackend.calls
50
+ )
51
+
52
+ def test_delivery_callback_wraps_user_callback(self) -> None:
53
+ """Test that the delivery callback wrapper calls both metrics and user callbacks"""
54
+ producer = ConfluentProducer(
55
+ {"bootstrap.servers": "fake:9092", "client.id": "test-producer-name"}
56
+ )
57
+ user_callback_invoked = []
58
+
59
+ def user_callback(
60
+ error: Optional[KafkaError], message: ConfluentMessage
61
+ ) -> None:
62
+ user_callback_invoked.append((error, message))
63
+
64
+ wrapped = producer._ConfluentProducer__delivery_callback(user_callback)
65
+ mock_message = mock.Mock(spec=ConfluentMessage)
66
+ wrapped(None, mock_message)
67
+ assert (
68
+ Increment(
69
+ "arroyo.producer.produce_status",
70
+ 1,
71
+ {"status": "success", "producer_name": "test-producer-name"},
72
+ )
73
+ in TestingMetricsBackend.calls
74
+ )
75
+ assert len(user_callback_invoked) == 1
76
+ assert user_callback_invoked[0] == (None, mock_message)
File without changes
File without changes
File without changes