sentry-arroyo 2.19.9__py3-none-any.whl → 2.19.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.
@@ -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.__is_incremental = (
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.__is_incremental:
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
- str, MutableMapping[Partition, int]
43
- ] = defaultdict(dict)
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.
arroyo/dlq.py CHANGED
@@ -49,7 +49,7 @@ class InvalidMessage(Exception):
49
49
  offset: int,
50
50
  needs_commit: bool = True,
51
51
  reason: Optional[str] = None,
52
- log_exception: bool = True
52
+ log_exception: bool = True,
53
53
  ) -> None:
54
54
  self.partition = partition
55
55
  self.offset = offset
@@ -208,7 +208,9 @@ class NoopDlqProducer(DlqProducer[Any]):
208
208
  """
209
209
 
210
210
  def produce(
211
- self, value: BrokerValue[KafkaPayload], reason: Optional[str] = None,
211
+ self,
212
+ value: BrokerValue[KafkaPayload],
213
+ reason: Optional[str] = None,
212
214
  ) -> Future[BrokerValue[KafkaPayload]]:
213
215
  future: Future[BrokerValue[KafkaPayload]] = Future()
214
216
  future.set_running_or_notify_cancel()
@@ -340,7 +342,7 @@ class DlqPolicyWrapper(Generic[TStrategyPayload]):
340
342
  self,
341
343
  policy: DlqPolicy[TStrategyPayload],
342
344
  ) -> None:
343
- self.MAX_PENDING_FUTURES = 1000 # This is a per partition max
345
+ self.MAX_PENDING_FUTURES = 2000 # This is a per partition max
344
346
  self.__dlq_policy = policy
345
347
 
346
348
  self.__futures: MutableMapping[
@@ -362,7 +364,9 @@ class DlqPolicyWrapper(Generic[TStrategyPayload]):
362
364
  self.__dlq_policy.limit, assignment
363
365
  )
364
366
 
365
- def produce(self, message: BrokerValue[TStrategyPayload], reason: Optional[str] = None) -> None:
367
+ def produce(
368
+ self, message: BrokerValue[TStrategyPayload], reason: Optional[str] = None
369
+ ) -> None:
366
370
  """
367
371
  Removes all completed futures, then appends the given future to the list.
368
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
- ProcessingStrategy[TStrategyPayload]
148
- ] = None
146
+ self.__processing_strategy: Optional[ProcessingStrategy[TStrategyPayload]] = (
147
+ None
148
+ )
149
149
 
150
150
  self.__message: Optional[BrokerValue[TStrategyPayload]] = None
151
151
 
@@ -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
- CommitPolicyState
60
- ] = commit_policy.get_state_machine()
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=max(deadline - time.time(), 0)
629
- if deadline is not None
630
- else None
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():
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: sentry-arroyo
3
- Version: 2.19.9
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.3.0
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
 
@@ -1,6 +1,6 @@
1
1
  arroyo/__init__.py,sha256=fcpHZd2P3MxWl6PJJ8n__fM_NRIfiUE8tKN-orv6lb0,187
2
2
  arroyo/commit.py,sha256=oFihWUW8fLsjomWh0o085qIHe9vwVNgoOJC6JQdFM7M,2235
3
- arroyo/dlq.py,sha256=BDmtJXrUKc8Pff7_AkRLE7accyyDkzakHe3mRPGJkNk,15631
3
+ arroyo/dlq.py,sha256=-mSckVjUZ2j1UgRcxsF5App78-5xb25EaW0zmHDMUH4,15662
4
4
  arroyo/errors.py,sha256=IbtoIbz_m5QrxNRBLOxiy-hOfJQTEwNPCyq6yqedJYk,1059
5
5
  arroyo/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  arroyo/types.py,sha256=sLY0x030np4UmbaW5C1KH1se7Z2pjQiPvAe5x2sXf7A,5684
@@ -9,20 +9,20 @@ arroyo/backends/abstract.py,sha256=PicUWWsgH-41XpHDcuq86P4PpPx7GWgLWdwnw4B0obo,7
9
9
  arroyo/backends/kafka/__init__.py,sha256=TZ0omd3LFXcZUaN_soFTuTgbjNEQYF1mF_i6_KIfCNo,306
10
10
  arroyo/backends/kafka/commit.py,sha256=LPsjvX5PPXR62DT6sa5GuSF78qk9F_L--Fz4kw7-m-s,3060
11
11
  arroyo/backends/kafka/configuration.py,sha256=D9zre9H2xagUsk7qBA-bm38V3_4Mg_X5hpKsKx2BkM8,3048
12
- arroyo/backends/kafka/consumer.py,sha256=sWqmn8jDf-wfZOXRc7vrotEepfeRbtdpzoP46VDf49A,27721
12
+ arroyo/backends/kafka/consumer.py,sha256=fo5a0tCq0XFvMA9drVCUCBMAXuA_x5KlpBU4G2LsNIo,27728
13
13
  arroyo/backends/local/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- arroyo/backends/local/backend.py,sha256=pQeZRUo9KDWlOT1pICWM0MvS39QuJqHnN5ryrmcxnSc,13878
14
+ arroyo/backends/local/backend.py,sha256=7odjCnzoGgdo8JHLgG1ntaXa-ZR9GteGkquiA2WAWmM,13880
15
15
  arroyo/backends/local/storages/__init__.py,sha256=AGYujdAAcn3osoj9jq84IzTywYbkIDv9wRg2rLhLXeg,104
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=RRLp8qcEL04TSvHaGuF0nc6RQ-HOiBzzI8nUwV5hZ2M,20025
19
+ arroyo/processing/processor.py,sha256=iTHQ8OI3rp6Pi43AWfnuAHC91eq9ZAp_i61-zsB1dq8,20027
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
23
23
  arroyo/processing/strategies/buffer.py,sha256=7s-tmXOMKlmvElZ6GKLOTjqTAfrrjS7AU_4b_kDHi7s,7066
24
24
  arroyo/processing/strategies/commit.py,sha256=F5QtYHA4nLeNWHCLFlVQTNCw2PpgTzX8HDDmhs-voLM,1413
25
- arroyo/processing/strategies/filter.py,sha256=RxR4wclEp-VfrgNfWe4TCTHzw33TMKJi5GaeHva7sqs,4871
25
+ arroyo/processing/strategies/filter.py,sha256=dzx9BaIVigxFGfsrNYAWJYTDCanIp3RiV91_dNHF5cc,4873
26
26
  arroyo/processing/strategies/guard.py,sha256=oC3XhyvYUg5CvSosUTXrCw9iA_hmN6EH2Lr-lpeOkI8,4875
27
27
  arroyo/processing/strategies/healthcheck.py,sha256=fEVB516nZVZWvZLzi4_ImaE6F7QQQJIymW6HgiUYUSA,1775
28
28
  arroyo/processing/strategies/noop.py,sha256=BtWkC93QpZCKAB4qTsXLaqrYsllE1Olp6mY2YeuK9ag,726
@@ -30,7 +30,7 @@ arroyo/processing/strategies/produce.py,sha256=v1mJv5rbyXal7ESIfsihbTGW-vZ0_niJn
30
30
  arroyo/processing/strategies/reduce.py,sha256=xv9bYisgHHyS8fVD1PdGi4TJsaK-4RAhMEDh4WHhYfI,3933
31
31
  arroyo/processing/strategies/run_task.py,sha256=MGe2UcIWN7FkPc9plKzRVUNbZ7Sk0jWjw1z2vVOFI_I,2160
32
32
  arroyo/processing/strategies/run_task_in_threads.py,sha256=f1sb2AG-BLz11X78jfhtERIkdFogrV8vtdT3pyJdkx0,6144
33
- arroyo/processing/strategies/run_task_with_multiprocessing.py,sha256=XhLRiMXFhZTRlxCTTmeI6SSTxy9SwiDHHiqq6mow-Z0,34409
33
+ arroyo/processing/strategies/run_task_with_multiprocessing.py,sha256=jNb_e3hcXDlnLE0XCgVjbLHXrob8V53aPGeMWtu4ToI,34417
34
34
  arroyo/processing/strategies/unfold.py,sha256=wZDNdMo1Ln27P1tUvLO2svhL-JDs2ZCyIFF2cq0DxVQ,3400
35
35
  arroyo/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
36
  arroyo/utils/clock.py,sha256=r2EMO4nL5qIb1xnAd1sTAk2yK1UltyUi04lk5BqWKIc,944
@@ -47,9 +47,9 @@ examples/transform_and_produce/batched.py,sha256=st2R6qTneAtV0JFbKP30Ti3sJDYj8Jk
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
49
  tests/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
- tests/backends/mixins.py,sha256=31t7B4a8cJ65XeUzv4ZoG9aPU1lTpDZXgkQrEyKhyqE,20131
50
+ tests/backends/mixins.py,sha256=sfNyE0VTeiD3GHOnBYl-9urvPuURI2G1BWke0cz7Dvc,20445
51
51
  tests/backends/test_commit.py,sha256=iTHfK1qsBxim0XwxgMvNNSMqDUMEHoYkYBDcgxGBFbs,831
52
- tests/backends/test_kafka.py,sha256=cB_GIY1yWT9w2VB1PWrvTr0lCa46r5uDfxisDFrcSmg,12089
52
+ tests/backends/test_kafka.py,sha256=mNwisb5PQPlBs5TIZtk6hL_eSbwAdwZ0RDD05WxDYps,12188
53
53
  tests/backends/test_local.py,sha256=Mfd4DFuWVSVtl1GomQ6TIoWuJNcAliKqKU0BShPlEMY,3363
54
54
  tests/processing/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
55
  tests/processing/test_processor.py,sha256=PDCrmhWAt_wZKwYlBzDuEGsd8PnjKM-p4ySaPvVd11k,20781
@@ -71,8 +71,8 @@ tests/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
71
  tests/utils/test_concurrent.py,sha256=Gwdzym2UZ1HO3rhOSGmzxImWcLFygY8P7MXHT3Q0xTE,455
72
72
  tests/utils/test_metrics.py,sha256=bI0EtGgPokMQyEqX58i0-8zvLfxRP2nWaWr2wLMaJ_o,917
73
73
  tests/utils/test_retries.py,sha256=AxJLkXWeL9AjHv_p1n0pe8CXXJp24ZQIuYBHfNcmiz4,3075
74
- sentry_arroyo-2.19.9.dist-info/LICENSE,sha256=0Ng3MFdEcnz0sVD1XvGBBzbavvNp_7OAM5yVObB46jU,10829
75
- sentry_arroyo-2.19.9.dist-info/METADATA,sha256=wmVhRiE5W4tvuCT3CCuAYsdi6q0ZjTPq8NxhA7zCuKA,1989
76
- sentry_arroyo-2.19.9.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
77
- sentry_arroyo-2.19.9.dist-info/top_level.txt,sha256=DVdMZKysL_iIxm5aY0sYgZtP5ZXMg9YBaBmGQHVmDXA,22
78
- sentry_arroyo-2.19.9.dist-info/RECORD,,
74
+ sentry_arroyo-2.19.10.dist-info/LICENSE,sha256=0Ng3MFdEcnz0sVD1XvGBBzbavvNp_7OAM5yVObB46jU,10829
75
+ sentry_arroyo-2.19.10.dist-info/METADATA,sha256=GS3IuMT7G1FFmRH6I3qVPW6GX1BtmN3uX9ji3XxYF70,2179
76
+ sentry_arroyo-2.19.10.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
77
+ sentry_arroyo-2.19.10.dist-info/top_level.txt,sha256=DVdMZKysL_iIxm5aY0sYgZtP5ZXMg9YBaBmGQHVmDXA,22
78
+ sentry_arroyo-2.19.10.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
tests/backends/mixins.py CHANGED
@@ -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(10):
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
- assert consumer_a.paused() == [Partition(topic, 1)]
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
- assert consumer_a_on_assign.mock_calls == [
487
- mock.call({Partition(topic, 0): 0, Partition(topic, 1): 0}),
488
- ]
489
- assert consumer_a_on_revoke.mock_calls == [
490
- mock.call([Partition(topic, 0)]),
491
- mock.call([Partition(topic, 1)]),
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
- assert consumer_b_on_assign.mock_calls == [
495
- mock.call({Partition(topic, 0): 0}),
496
- mock.call({Partition(topic, 1): 0}),
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(