sentry-arroyo 2.19.8__tar.gz → 2.19.10__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.
- {sentry_arroyo-2.19.8/sentry_arroyo.egg-info → sentry_arroyo-2.19.10}/PKG-INFO +12 -3
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/backends/kafka/consumer.py +3 -3
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/backends/local/backend.py +3 -3
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/dlq.py +14 -4
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/processor.py +5 -4
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/filter.py +3 -3
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/run_task_with_multiprocessing.py +3 -3
- sentry_arroyo-2.19.10/requirements.txt +1 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10/sentry_arroyo.egg-info}/PKG-INFO +12 -3
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/sentry_arroyo.egg-info/SOURCES.txt +1 -0
- sentry_arroyo-2.19.10/sentry_arroyo.egg-info/requires.txt +1 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/setup.py +1 -1
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/backends/mixins.py +25 -15
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/backends/test_kafka.py +4 -1
- sentry_arroyo-2.19.10/tests/test_kip848_e2e.py +114 -0
- sentry_arroyo-2.19.8/requirements.txt +0 -1
- sentry_arroyo-2.19.8/sentry_arroyo.egg-info/requires.txt +0 -1
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/LICENSE +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/MANIFEST.in +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/README.md +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/__init__.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/backends/__init__.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/backends/abstract.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/backends/kafka/__init__.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/backends/kafka/commit.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/backends/kafka/configuration.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/backends/local/__init__.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/backends/local/storages/__init__.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/backends/local/storages/abstract.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/backends/local/storages/memory.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/commit.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/errors.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/__init__.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/__init__.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/abstract.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/batching.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/buffer.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/commit.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/guard.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/healthcheck.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/noop.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/produce.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/reduce.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/run_task.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/run_task_in_threads.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/unfold.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/py.typed +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/types.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/utils/__init__.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/utils/clock.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/utils/codecs.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/utils/concurrent.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/utils/logging.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/utils/metricDefs.json +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/utils/metric_defs.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/utils/metrics.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/utils/profiler.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/utils/retries.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/examples/transform_and_produce/__init__.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/examples/transform_and_produce/batched.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/examples/transform_and_produce/script.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/examples/transform_and_produce/simple.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/sentry_arroyo.egg-info/dependency_links.txt +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/sentry_arroyo.egg-info/not-zip-safe +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/sentry_arroyo.egg-info/top_level.txt +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/setup.cfg +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/backends/__init__.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/backends/test_commit.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/backends/test_local.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/__init__.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/__init__.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/test_all.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/test_batching.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/test_buffer.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/test_commit.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/test_filter.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/test_guard.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/test_noop.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/test_produce.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/test_reduce.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/test_run_task.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/test_run_task_in_threads.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/test_run_task_with_multiprocessing.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/strategies/test_unfold.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/processing/test_processor.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/test_commit.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/test_dlq.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/test_types.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/utils/__init__.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/utils/test_concurrent.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/utils/test_metrics.py +0 -0
- {sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/tests/utils/test_retries.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: sentry-arroyo
|
|
3
|
-
Version: 2.19.
|
|
3
|
+
Version: 2.19.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
|
|
@@ -13,7 +13,16 @@ Classifier: Programming Language :: Python
|
|
|
13
13
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
License-File: LICENSE
|
|
16
|
-
Requires-Dist: confluent-kafka>=2.
|
|
16
|
+
Requires-Dist: confluent-kafka>=2.7.0
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: author-email
|
|
19
|
+
Dynamic: classifier
|
|
20
|
+
Dynamic: description
|
|
21
|
+
Dynamic: description-content-type
|
|
22
|
+
Dynamic: home-page
|
|
23
|
+
Dynamic: license
|
|
24
|
+
Dynamic: requires-dist
|
|
25
|
+
Dynamic: summary
|
|
17
26
|
|
|
18
27
|
# Arroyo
|
|
19
28
|
|
|
@@ -157,13 +157,13 @@ class KafkaConsumer(Consumer[KafkaPayload]):
|
|
|
157
157
|
KafkaError.REQUEST_TIMED_OUT,
|
|
158
158
|
KafkaError.NOT_COORDINATOR,
|
|
159
159
|
KafkaError._WAIT_COORD,
|
|
160
|
+
KafkaError.STALE_MEMBER_EPOCH, # kip-848
|
|
160
161
|
),
|
|
161
162
|
)
|
|
162
163
|
|
|
163
164
|
configuration = dict(configuration)
|
|
164
|
-
self.
|
|
165
|
+
self.__is_cooperative_sticky = (
|
|
165
166
|
configuration.get("partition.assignment.strategy") == "cooperative-sticky"
|
|
166
|
-
or configuration.get("group.protocol") == "consumer"
|
|
167
167
|
)
|
|
168
168
|
auto_offset_reset = configuration.get("auto.offset.reset", "largest")
|
|
169
169
|
|
|
@@ -463,7 +463,7 @@ class KafkaConsumer(Consumer[KafkaPayload]):
|
|
|
463
463
|
ConfluentTopicPartition(partition.topic.name, partition.index, offset)
|
|
464
464
|
for partition, offset in offsets.items()
|
|
465
465
|
]
|
|
466
|
-
if self.
|
|
466
|
+
if self.__is_cooperative_sticky:
|
|
467
467
|
self.__consumer.incremental_assign(partitions)
|
|
468
468
|
else:
|
|
469
469
|
self.__consumer.assign(partitions)
|
|
@@ -38,9 +38,9 @@ class LocalBroker(Generic[TStrategyPayload]):
|
|
|
38
38
|
self.__message_storage = message_storage
|
|
39
39
|
self.__clock = clock
|
|
40
40
|
|
|
41
|
-
self.__offsets: MutableMapping[
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
self.__offsets: MutableMapping[str, MutableMapping[Partition, int]] = (
|
|
42
|
+
defaultdict(dict)
|
|
43
|
+
)
|
|
44
44
|
|
|
45
45
|
# The active subscriptions are stored by consumer group as a mapping
|
|
46
46
|
# between the consumer and it's subscribed topics.
|
|
@@ -44,12 +44,18 @@ class InvalidMessage(Exception):
|
|
|
44
44
|
"""
|
|
45
45
|
|
|
46
46
|
def __init__(
|
|
47
|
-
self,
|
|
47
|
+
self,
|
|
48
|
+
partition: Partition,
|
|
49
|
+
offset: int,
|
|
50
|
+
needs_commit: bool = True,
|
|
51
|
+
reason: Optional[str] = None,
|
|
52
|
+
log_exception: bool = True,
|
|
48
53
|
) -> None:
|
|
49
54
|
self.partition = partition
|
|
50
55
|
self.offset = offset
|
|
51
56
|
self.needs_commit = needs_commit
|
|
52
57
|
self.reason = reason
|
|
58
|
+
self.log_exception = log_exception
|
|
53
59
|
|
|
54
60
|
@classmethod
|
|
55
61
|
def from_value(cls, value: BrokerValue[Any]) -> InvalidMessage:
|
|
@@ -202,7 +208,9 @@ class NoopDlqProducer(DlqProducer[Any]):
|
|
|
202
208
|
"""
|
|
203
209
|
|
|
204
210
|
def produce(
|
|
205
|
-
self,
|
|
211
|
+
self,
|
|
212
|
+
value: BrokerValue[KafkaPayload],
|
|
213
|
+
reason: Optional[str] = None,
|
|
206
214
|
) -> Future[BrokerValue[KafkaPayload]]:
|
|
207
215
|
future: Future[BrokerValue[KafkaPayload]] = Future()
|
|
208
216
|
future.set_running_or_notify_cancel()
|
|
@@ -334,7 +342,7 @@ class DlqPolicyWrapper(Generic[TStrategyPayload]):
|
|
|
334
342
|
self,
|
|
335
343
|
policy: DlqPolicy[TStrategyPayload],
|
|
336
344
|
) -> None:
|
|
337
|
-
self.MAX_PENDING_FUTURES =
|
|
345
|
+
self.MAX_PENDING_FUTURES = 2000 # This is a per partition max
|
|
338
346
|
self.__dlq_policy = policy
|
|
339
347
|
|
|
340
348
|
self.__futures: MutableMapping[
|
|
@@ -356,7 +364,9 @@ class DlqPolicyWrapper(Generic[TStrategyPayload]):
|
|
|
356
364
|
self.__dlq_policy.limit, assignment
|
|
357
365
|
)
|
|
358
366
|
|
|
359
|
-
def produce(
|
|
367
|
+
def produce(
|
|
368
|
+
self, message: BrokerValue[TStrategyPayload], reason: Optional[str] = None
|
|
369
|
+
) -> None:
|
|
360
370
|
"""
|
|
361
371
|
Removes all completed futures, then appends the given future to the list.
|
|
362
372
|
Blocks if the list is full. If the DLQ limit is exceeded, an exception is raised.
|
|
@@ -143,9 +143,9 @@ class StreamProcessor(Generic[TStrategyPayload]):
|
|
|
143
143
|
self.__processor_factory = processor_factory
|
|
144
144
|
self.__metrics_buffer = MetricsBuffer()
|
|
145
145
|
|
|
146
|
-
self.__processing_strategy: Optional[
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
self.__processing_strategy: Optional[ProcessingStrategy[TStrategyPayload]] = (
|
|
147
|
+
None
|
|
148
|
+
)
|
|
149
149
|
|
|
150
150
|
self.__message: Optional[BrokerValue[TStrategyPayload]] = None
|
|
151
151
|
|
|
@@ -365,7 +365,8 @@ class StreamProcessor(Generic[TStrategyPayload]):
|
|
|
365
365
|
):
|
|
366
366
|
self.__message = None
|
|
367
367
|
|
|
368
|
-
|
|
368
|
+
if exc.log_exception:
|
|
369
|
+
logger.exception(exc)
|
|
369
370
|
self.__metrics_buffer.incr_counter("arroyo.consumer.invalid_message.count", 1)
|
|
370
371
|
if self.__dlq_policy:
|
|
371
372
|
start_dlq = time.time()
|
|
@@ -55,9 +55,9 @@ class FilterStep(ProcessingStrategy[Union[FilteredPayload, TStrategyPayload]]):
|
|
|
55
55
|
self.__next_step = next_step
|
|
56
56
|
|
|
57
57
|
if commit_policy is not None:
|
|
58
|
-
self.__commit_policy_state: Optional[
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
self.__commit_policy_state: Optional[CommitPolicyState] = (
|
|
59
|
+
commit_policy.get_state_machine()
|
|
60
|
+
)
|
|
61
61
|
else:
|
|
62
62
|
self.__commit_policy_state = None
|
|
63
63
|
|
|
@@ -625,9 +625,9 @@ class RunTaskWithMultiprocessing(
|
|
|
625
625
|
while self.__processes:
|
|
626
626
|
try:
|
|
627
627
|
self.__check_for_results_impl(
|
|
628
|
-
timeout=
|
|
629
|
-
|
|
630
|
-
|
|
628
|
+
timeout=(
|
|
629
|
+
max(deadline - time.time(), 0) if deadline is not None else None
|
|
630
|
+
)
|
|
631
631
|
)
|
|
632
632
|
except NextStepTimeoutError:
|
|
633
633
|
if deadline is None or deadline > time.time():
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
confluent-kafka>=2.7.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: sentry-arroyo
|
|
3
|
-
Version: 2.19.
|
|
3
|
+
Version: 2.19.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
|
|
@@ -13,7 +13,16 @@ Classifier: Programming Language :: Python
|
|
|
13
13
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
14
|
Description-Content-Type: text/markdown
|
|
15
15
|
License-File: LICENSE
|
|
16
|
-
Requires-Dist: confluent-kafka>=2.
|
|
16
|
+
Requires-Dist: confluent-kafka>=2.7.0
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: author-email
|
|
19
|
+
Dynamic: classifier
|
|
20
|
+
Dynamic: description
|
|
21
|
+
Dynamic: description-content-type
|
|
22
|
+
Dynamic: home-page
|
|
23
|
+
Dynamic: license
|
|
24
|
+
Dynamic: requires-dist
|
|
25
|
+
Dynamic: summary
|
|
17
26
|
|
|
18
27
|
# Arroyo
|
|
19
28
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
confluent-kafka>=2.7.0
|
|
@@ -15,6 +15,7 @@ from tests.assertions import assert_changes, assert_does_not_change
|
|
|
15
15
|
|
|
16
16
|
class StreamsTestMixin(ABC, Generic[TStrategyPayload]):
|
|
17
17
|
cooperative_sticky = False
|
|
18
|
+
kip_848 = False
|
|
18
19
|
|
|
19
20
|
@abstractmethod
|
|
20
21
|
def get_topic(self, partitions: int = 1) -> ContextManager[Topic]:
|
|
@@ -421,7 +422,7 @@ class StreamsTestMixin(ABC, Generic[TStrategyPayload]):
|
|
|
421
422
|
def wait_until_rebalancing(
|
|
422
423
|
from_consumer: Consumer[Any], to_consumer: Consumer[Any]
|
|
423
424
|
) -> None:
|
|
424
|
-
for _ in range(
|
|
425
|
+
for _ in range(20):
|
|
425
426
|
assert from_consumer.poll(0) is None
|
|
426
427
|
if to_consumer.poll(1.0) is not None:
|
|
427
428
|
return
|
|
@@ -453,9 +454,10 @@ class StreamsTestMixin(ABC, Generic[TStrategyPayload]):
|
|
|
453
454
|
|
|
454
455
|
wait_until_rebalancing(consumer_a, consumer_b)
|
|
455
456
|
|
|
456
|
-
if self.cooperative_sticky:
|
|
457
|
+
if self.cooperative_sticky or self.kip_848:
|
|
457
458
|
# within incremental rebalancing, only one partition should have been reassigned to the consumer_b, and consumer_a should remain paused
|
|
458
|
-
|
|
459
|
+
# Either partition 0 or 1 might be the paused one
|
|
460
|
+
assert len(consumer_a.paused()) == 1
|
|
459
461
|
assert consumer_a.poll(10.0) is None
|
|
460
462
|
else:
|
|
461
463
|
# The first consumer should have had its offsets rolled back, as
|
|
@@ -481,20 +483,28 @@ class StreamsTestMixin(ABC, Generic[TStrategyPayload]):
|
|
|
481
483
|
|
|
482
484
|
assert len(consumer_b.tell()) == 2
|
|
483
485
|
|
|
484
|
-
if self.cooperative_sticky:
|
|
486
|
+
if self.cooperative_sticky or self.kip_848:
|
|
487
|
+
consumer_a_on_assign.assert_has_calls(
|
|
488
|
+
[
|
|
489
|
+
mock.call({Partition(topic, 0): 0, Partition(topic, 1): 0}),
|
|
490
|
+
]
|
|
491
|
+
)
|
|
485
492
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
+
consumer_a_on_revoke.assert_has_calls(
|
|
494
|
+
[
|
|
495
|
+
mock.call([Partition(topic, 0)]),
|
|
496
|
+
mock.call([Partition(topic, 1)]),
|
|
497
|
+
],
|
|
498
|
+
any_order=True,
|
|
499
|
+
)
|
|
493
500
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
501
|
+
consumer_b_on_assign.assert_has_calls(
|
|
502
|
+
[
|
|
503
|
+
mock.call({Partition(topic, 0): 0}),
|
|
504
|
+
mock.call({Partition(topic, 1): 0}),
|
|
505
|
+
],
|
|
506
|
+
any_order=True,
|
|
507
|
+
)
|
|
498
508
|
assert consumer_b_on_revoke.mock_calls == []
|
|
499
509
|
else:
|
|
500
510
|
assert consumer_a_on_assign.mock_calls == [
|
|
@@ -271,10 +271,13 @@ class TestKafkaStreamsIncrementalRebalancing(TestKafkaStreams):
|
|
|
271
271
|
cooperative_sticky = True
|
|
272
272
|
|
|
273
273
|
|
|
274
|
-
@pytest.mark.skip("kip-848 not functional yet")
|
|
275
274
|
class TestKafkaStreamsKip848(TestKafkaStreams):
|
|
276
275
|
kip_848 = True
|
|
277
276
|
|
|
277
|
+
@pytest.mark.xfail(reason="To be fixed")
|
|
278
|
+
def test_pause_resume_rebalancing(self) -> None:
|
|
279
|
+
super().test_pause_resume_rebalancing()
|
|
280
|
+
|
|
278
281
|
|
|
279
282
|
def test_commit_codec() -> None:
|
|
280
283
|
commit = Commit(
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
import contextlib
|
|
5
|
+
from contextlib import closing
|
|
6
|
+
import os
|
|
7
|
+
import threading
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Iterator, Mapping
|
|
10
|
+
|
|
11
|
+
from confluent_kafka.admin import AdminClient, NewTopic
|
|
12
|
+
from arroyo.types import Commit, Message, Partition, Topic
|
|
13
|
+
from arroyo.backends.kafka.configuration import build_kafka_consumer_configuration
|
|
14
|
+
from arroyo.backends.kafka.consumer import KafkaConsumer, KafkaPayload
|
|
15
|
+
from arroyo.processing.strategies import RunTask, CommitOffsets, ProcessingStrategy
|
|
16
|
+
from arroyo.processing.strategies.abstract import ProcessingStrategyFactory
|
|
17
|
+
from arroyo.processing.processor import StreamProcessor
|
|
18
|
+
from arroyo.backends.kafka import KafkaProducer
|
|
19
|
+
|
|
20
|
+
logging.basicConfig(level=logging.INFO)
|
|
21
|
+
|
|
22
|
+
TOPIC = "test-kip848"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@contextlib.contextmanager
|
|
26
|
+
def get_topic(
|
|
27
|
+
configuration: Mapping[str, Any], partitions_count: int
|
|
28
|
+
) -> Iterator[Topic]:
|
|
29
|
+
name = TOPIC
|
|
30
|
+
configuration = dict(configuration)
|
|
31
|
+
client = AdminClient(configuration)
|
|
32
|
+
[[key, future]] = client.create_topics(
|
|
33
|
+
[NewTopic(name, num_partitions=partitions_count, replication_factor=1)]
|
|
34
|
+
).items()
|
|
35
|
+
assert key == name
|
|
36
|
+
assert future.result() is None
|
|
37
|
+
try:
|
|
38
|
+
yield Topic(name)
|
|
39
|
+
finally:
|
|
40
|
+
[[key, future]] = client.delete_topics([name]).items()
|
|
41
|
+
assert key == name
|
|
42
|
+
assert future.result() is None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_kip848_e2e() -> None:
|
|
46
|
+
counter = 0
|
|
47
|
+
|
|
48
|
+
def print_msg(message: Message[Any]) -> Message[Any]:
|
|
49
|
+
nonlocal counter
|
|
50
|
+
((partition, offset),) = message.committable.items()
|
|
51
|
+
print(f"message: {partition.index}-{offset}")
|
|
52
|
+
counter += 1
|
|
53
|
+
return message
|
|
54
|
+
|
|
55
|
+
class Strat(RunTask[Any, Any]):
|
|
56
|
+
def join(self, *args: Any, **kwargs: Any) -> None:
|
|
57
|
+
print("joining strategy, sleeping 5 seconds")
|
|
58
|
+
time.sleep(5)
|
|
59
|
+
print("joining strategy, sleeping 5 seconds -- DONE")
|
|
60
|
+
return super().join(*args, **kwargs)
|
|
61
|
+
|
|
62
|
+
class Factory(ProcessingStrategyFactory[KafkaPayload]):
|
|
63
|
+
def create_with_partitions(
|
|
64
|
+
self, commit: Commit, partitions: Mapping[Partition, int]
|
|
65
|
+
) -> ProcessingStrategy[KafkaPayload]:
|
|
66
|
+
print("assign: ", [p.index for p in partitions])
|
|
67
|
+
return Strat(print_msg, CommitOffsets(commit))
|
|
68
|
+
|
|
69
|
+
default_config = {
|
|
70
|
+
"bootstrap.servers": os.environ.get("DEFAULT_BROKERS", "localhost:9092")
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
with get_topic(default_config, 2) as topic:
|
|
74
|
+
producer = KafkaProducer(default_config)
|
|
75
|
+
|
|
76
|
+
with closing(producer):
|
|
77
|
+
for i in range(30):
|
|
78
|
+
message = KafkaPayload(None, i.to_bytes(1, "big"), [])
|
|
79
|
+
producer.produce(topic, message).result()
|
|
80
|
+
|
|
81
|
+
consumer_config = build_kafka_consumer_configuration(
|
|
82
|
+
default_config,
|
|
83
|
+
group_id="kip848",
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
consumer_config["group.protocol"] = "consumer"
|
|
87
|
+
consumer_config.pop("session.timeout.ms", None)
|
|
88
|
+
consumer_config.pop("max.poll.interval.ms", None)
|
|
89
|
+
consumer_config.pop("partition.assignment.strategy", None)
|
|
90
|
+
consumer_config.pop("group.protocol.type", None)
|
|
91
|
+
consumer_config.pop("heartbeat.interval.ms", None)
|
|
92
|
+
|
|
93
|
+
consumer = KafkaConsumer(consumer_config)
|
|
94
|
+
|
|
95
|
+
processor = StreamProcessor(
|
|
96
|
+
consumer=consumer, topic=Topic(TOPIC), processor_factory=Factory()
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
def shutdown() -> None:
|
|
100
|
+
for i in range(100):
|
|
101
|
+
time.sleep(0.1)
|
|
102
|
+
if counter == 30:
|
|
103
|
+
break
|
|
104
|
+
print("shutting down")
|
|
105
|
+
processor.signal_shutdown()
|
|
106
|
+
|
|
107
|
+
t = threading.Thread(target=shutdown)
|
|
108
|
+
t.start()
|
|
109
|
+
|
|
110
|
+
processor.run()
|
|
111
|
+
|
|
112
|
+
assert counter == 30
|
|
113
|
+
|
|
114
|
+
t.join()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
confluent-kafka>=2.3.0
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
confluent-kafka>=2.3.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sentry_arroyo-2.19.8 → sentry_arroyo-2.19.10}/arroyo/processing/strategies/run_task_in_threads.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|