kafka-python 3.0.0__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.
Files changed (373) hide show
  1. kafka/__init__.py +34 -0
  2. kafka/__main__.py +5 -0
  3. kafka/admin/__init__.py +29 -0
  4. kafka/admin/__main__.py +5 -0
  5. kafka/admin/_acls.py +355 -0
  6. kafka/admin/_cluster.py +359 -0
  7. kafka/admin/_configs.py +479 -0
  8. kafka/admin/_groups.py +754 -0
  9. kafka/admin/_partitions.py +595 -0
  10. kafka/admin/_topics.py +281 -0
  11. kafka/admin/_transactions.py +450 -0
  12. kafka/admin/_users.py +194 -0
  13. kafka/admin/client.py +373 -0
  14. kafka/benchmarks/__init__.py +0 -0
  15. kafka/benchmarks/consumer_performance.py +138 -0
  16. kafka/benchmarks/load_example.py +109 -0
  17. kafka/benchmarks/producer_encode_path.py +201 -0
  18. kafka/benchmarks/producer_performance.py +161 -0
  19. kafka/benchmarks/profile_protocol.py +138 -0
  20. kafka/benchmarks/protocol_old_vs_new.py +447 -0
  21. kafka/benchmarks/record_batch_compose.py +77 -0
  22. kafka/benchmarks/record_batch_read.py +82 -0
  23. kafka/benchmarks/varint_speed.py +426 -0
  24. kafka/cli/__init__.py +36 -0
  25. kafka/cli/admin/__init__.py +117 -0
  26. kafka/cli/admin/acls/__init__.py +9 -0
  27. kafka/cli/admin/acls/common.py +76 -0
  28. kafka/cli/admin/acls/create.py +19 -0
  29. kafka/cli/admin/acls/delete.py +23 -0
  30. kafka/cli/admin/acls/describe.py +16 -0
  31. kafka/cli/admin/cluster/__init__.py +14 -0
  32. kafka/cli/admin/cluster/describe.py +11 -0
  33. kafka/cli/admin/cluster/describe_quorum.py +11 -0
  34. kafka/cli/admin/cluster/features.py +52 -0
  35. kafka/cli/admin/cluster/log_dirs.py +43 -0
  36. kafka/cli/admin/cluster/versions.py +33 -0
  37. kafka/cli/admin/configs/__init__.py +10 -0
  38. kafka/cli/admin/configs/alter.py +43 -0
  39. kafka/cli/admin/configs/common.py +17 -0
  40. kafka/cli/admin/configs/describe.py +30 -0
  41. kafka/cli/admin/configs/list.py +16 -0
  42. kafka/cli/admin/configs/reset.py +20 -0
  43. kafka/cli/admin/groups/__init__.py +16 -0
  44. kafka/cli/admin/groups/alter_offsets.py +30 -0
  45. kafka/cli/admin/groups/delete.py +11 -0
  46. kafka/cli/admin/groups/delete_offsets.py +29 -0
  47. kafka/cli/admin/groups/describe.py +11 -0
  48. kafka/cli/admin/groups/list.py +28 -0
  49. kafka/cli/admin/groups/list_offsets.py +29 -0
  50. kafka/cli/admin/groups/remove_members.py +40 -0
  51. kafka/cli/admin/groups/reset_offsets.py +139 -0
  52. kafka/cli/admin/partitions/__init__.py +21 -0
  53. kafka/cli/admin/partitions/alter_reassignments.py +37 -0
  54. kafka/cli/admin/partitions/create.py +27 -0
  55. kafka/cli/admin/partitions/delete_records.py +31 -0
  56. kafka/cli/admin/partitions/describe.py +36 -0
  57. kafka/cli/admin/partitions/elect_leaders.py +53 -0
  58. kafka/cli/admin/partitions/list_offsets.py +88 -0
  59. kafka/cli/admin/partitions/list_reassignments.py +35 -0
  60. kafka/cli/admin/topics/__init__.py +10 -0
  61. kafka/cli/admin/topics/create.py +13 -0
  62. kafka/cli/admin/topics/delete.py +19 -0
  63. kafka/cli/admin/topics/describe.py +18 -0
  64. kafka/cli/admin/topics/list.py +11 -0
  65. kafka/cli/admin/transactions/__init__.py +17 -0
  66. kafka/cli/admin/transactions/abort.py +38 -0
  67. kafka/cli/admin/transactions/describe.py +24 -0
  68. kafka/cli/admin/transactions/describe_producers.py +29 -0
  69. kafka/cli/admin/transactions/find_hanging.py +26 -0
  70. kafka/cli/admin/transactions/list.py +37 -0
  71. kafka/cli/admin/users/__init__.py +8 -0
  72. kafka/cli/admin/users/alter_user_scram_credentials.py +34 -0
  73. kafka/cli/admin/users/describe_user_scram_credentials.py +15 -0
  74. kafka/cli/common.py +95 -0
  75. kafka/cli/consumer/__init__.py +63 -0
  76. kafka/cli/producer/__init__.py +57 -0
  77. kafka/cluster.py +824 -0
  78. kafka/codec.py +325 -0
  79. kafka/consumer/__init__.py +5 -0
  80. kafka/consumer/__main__.py +5 -0
  81. kafka/consumer/fetcher.py +2012 -0
  82. kafka/consumer/group.py +1347 -0
  83. kafka/consumer/subscription_state.py +897 -0
  84. kafka/coordinator/__init__.py +0 -0
  85. kafka/coordinator/assignors/__init__.py +0 -0
  86. kafka/coordinator/assignors/abstract.py +90 -0
  87. kafka/coordinator/assignors/cooperative_sticky.py +167 -0
  88. kafka/coordinator/assignors/range.py +81 -0
  89. kafka/coordinator/assignors/roundrobin.py +101 -0
  90. kafka/coordinator/assignors/sticky/StickyAssignorUserData.json +37 -0
  91. kafka/coordinator/assignors/sticky/__init__.py +0 -0
  92. kafka/coordinator/assignors/sticky/partition_movements.py +149 -0
  93. kafka/coordinator/assignors/sticky/sorted_set.py +63 -0
  94. kafka/coordinator/assignors/sticky/sticky_assignor.py +665 -0
  95. kafka/coordinator/assignors/sticky/user_data.py +8 -0
  96. kafka/coordinator/base.py +1215 -0
  97. kafka/coordinator/consumer.py +1224 -0
  98. kafka/coordinator/heartbeat.py +82 -0
  99. kafka/coordinator/subscription.py +34 -0
  100. kafka/errors.py +1004 -0
  101. kafka/future.py +166 -0
  102. kafka/metrics/__init__.py +13 -0
  103. kafka/metrics/compound_stat.py +33 -0
  104. kafka/metrics/dict_reporter.py +81 -0
  105. kafka/metrics/kafka_metric.py +36 -0
  106. kafka/metrics/measurable.py +27 -0
  107. kafka/metrics/measurable_stat.py +13 -0
  108. kafka/metrics/metric_config.py +33 -0
  109. kafka/metrics/metric_name.py +105 -0
  110. kafka/metrics/metrics.py +261 -0
  111. kafka/metrics/metrics_reporter.py +53 -0
  112. kafka/metrics/quota.py +41 -0
  113. kafka/metrics/stat.py +19 -0
  114. kafka/metrics/stats/__init__.py +15 -0
  115. kafka/metrics/stats/avg.py +24 -0
  116. kafka/metrics/stats/count.py +17 -0
  117. kafka/metrics/stats/histogram.py +99 -0
  118. kafka/metrics/stats/max_stat.py +17 -0
  119. kafka/metrics/stats/min_stat.py +19 -0
  120. kafka/metrics/stats/percentile.py +14 -0
  121. kafka/metrics/stats/percentiles.py +75 -0
  122. kafka/metrics/stats/rate.py +118 -0
  123. kafka/metrics/stats/sampled_stat.py +99 -0
  124. kafka/metrics/stats/sensor.py +136 -0
  125. kafka/metrics/stats/total.py +15 -0
  126. kafka/net/__init__.py +19 -0
  127. kafka/net/compat.py +165 -0
  128. kafka/net/connection.py +593 -0
  129. kafka/net/http_connect.py +144 -0
  130. kafka/net/inet.py +122 -0
  131. kafka/net/manager.py +451 -0
  132. kafka/net/metrics.py +149 -0
  133. kafka/net/sasl/__init__.py +32 -0
  134. kafka/net/sasl/abc.py +28 -0
  135. kafka/net/sasl/gssapi.py +95 -0
  136. kafka/net/sasl/msk.py +245 -0
  137. kafka/net/sasl/oauth.py +98 -0
  138. kafka/net/sasl/plain.py +42 -0
  139. kafka/net/sasl/scram.py +135 -0
  140. kafka/net/sasl/sspi.py +111 -0
  141. kafka/net/selector.py +644 -0
  142. kafka/net/socks5.py +262 -0
  143. kafka/net/transport.py +415 -0
  144. kafka/net/wakeup_notifier.py +72 -0
  145. kafka/partitioner/__init__.py +8 -0
  146. kafka/partitioner/abc.py +8 -0
  147. kafka/partitioner/default.py +89 -0
  148. kafka/partitioner/sticky.py +109 -0
  149. kafka/producer/__init__.py +5 -0
  150. kafka/producer/__main__.py +5 -0
  151. kafka/producer/future.py +101 -0
  152. kafka/producer/kafka.py +1123 -0
  153. kafka/producer/producer_batch.py +192 -0
  154. kafka/producer/record_accumulator.py +647 -0
  155. kafka/producer/sender.py +884 -0
  156. kafka/producer/transaction_manager.py +1326 -0
  157. kafka/protocol/__init__.py +0 -0
  158. kafka/protocol/admin/__init__.py +29 -0
  159. kafka/protocol/admin/acl.py +83 -0
  160. kafka/protocol/admin/acl.pyi +375 -0
  161. kafka/protocol/admin/client_quotas.py +14 -0
  162. kafka/protocol/admin/client_quotas.pyi +265 -0
  163. kafka/protocol/admin/cluster.py +31 -0
  164. kafka/protocol/admin/cluster.pyi +620 -0
  165. kafka/protocol/admin/configs.py +22 -0
  166. kafka/protocol/admin/configs.pyi +437 -0
  167. kafka/protocol/admin/groups.py +24 -0
  168. kafka/protocol/admin/groups.pyi +261 -0
  169. kafka/protocol/admin/topics.py +53 -0
  170. kafka/protocol/admin/topics.pyi +982 -0
  171. kafka/protocol/admin/transactions.py +18 -0
  172. kafka/protocol/admin/transactions.pyi +311 -0
  173. kafka/protocol/admin/users.py +14 -0
  174. kafka/protocol/admin/users.pyi +223 -0
  175. kafka/protocol/api_data.py +125 -0
  176. kafka/protocol/api_header.py +55 -0
  177. kafka/protocol/api_key.py +97 -0
  178. kafka/protocol/api_message.py +277 -0
  179. kafka/protocol/broker_version_data.py +246 -0
  180. kafka/protocol/consumer/__init__.py +13 -0
  181. kafka/protocol/consumer/fetch.py +16 -0
  182. kafka/protocol/consumer/fetch.pyi +298 -0
  183. kafka/protocol/consumer/group.py +38 -0
  184. kafka/protocol/consumer/group.pyi +824 -0
  185. kafka/protocol/consumer/metadata.py +30 -0
  186. kafka/protocol/consumer/metadata.pyi +89 -0
  187. kafka/protocol/consumer/offsets.py +75 -0
  188. kafka/protocol/consumer/offsets.pyi +288 -0
  189. kafka/protocol/data_container.py +166 -0
  190. kafka/protocol/frame.py +30 -0
  191. kafka/protocol/generate_stubs.py +468 -0
  192. kafka/protocol/metadata/__init__.py +10 -0
  193. kafka/protocol/metadata/api_versions.py +41 -0
  194. kafka/protocol/metadata/api_versions.pyi +128 -0
  195. kafka/protocol/metadata/find_coordinator.py +19 -0
  196. kafka/protocol/metadata/find_coordinator.pyi +105 -0
  197. kafka/protocol/metadata/metadata.py +34 -0
  198. kafka/protocol/metadata/metadata.pyi +160 -0
  199. kafka/protocol/old/__init__.py +0 -0
  200. kafka/protocol/old/abstract.py +17 -0
  201. kafka/protocol/old/add_offsets_to_txn.py +54 -0
  202. kafka/protocol/old/add_partitions_to_txn.py +71 -0
  203. kafka/protocol/old/admin.py +1086 -0
  204. kafka/protocol/old/api.py +205 -0
  205. kafka/protocol/old/api_versions.py +133 -0
  206. kafka/protocol/old/commit.py +355 -0
  207. kafka/protocol/old/consumer_protocol.py +36 -0
  208. kafka/protocol/old/end_txn.py +53 -0
  209. kafka/protocol/old/fetch.py +408 -0
  210. kafka/protocol/old/find_coordinator.py +72 -0
  211. kafka/protocol/old/group.py +451 -0
  212. kafka/protocol/old/init_producer_id.py +42 -0
  213. kafka/protocol/old/list_offsets.py +186 -0
  214. kafka/protocol/old/metadata.py +290 -0
  215. kafka/protocol/old/offset_for_leader_epoch.py +133 -0
  216. kafka/protocol/old/produce.py +247 -0
  217. kafka/protocol/old/sasl_authenticate.py +38 -0
  218. kafka/protocol/old/sasl_handshake.py +39 -0
  219. kafka/protocol/old/struct.py +87 -0
  220. kafka/protocol/old/txn_offset_commit.py +73 -0
  221. kafka/protocol/old/types.py +440 -0
  222. kafka/protocol/parser.py +191 -0
  223. kafka/protocol/producer/__init__.py +7 -0
  224. kafka/protocol/producer/produce.py +17 -0
  225. kafka/protocol/producer/produce.pyi +197 -0
  226. kafka/protocol/producer/transaction.py +30 -0
  227. kafka/protocol/producer/transaction.pyi +663 -0
  228. kafka/protocol/sasl.py +52 -0
  229. kafka/protocol/sasl.pyi +126 -0
  230. kafka/protocol/schemas/__init__.py +7 -0
  231. kafka/protocol/schemas/fields/__init__.py +7 -0
  232. kafka/protocol/schemas/fields/array.py +127 -0
  233. kafka/protocol/schemas/fields/base.py +156 -0
  234. kafka/protocol/schemas/fields/codecs/__init__.py +12 -0
  235. kafka/protocol/schemas/fields/codecs/encode_buffer.py +82 -0
  236. kafka/protocol/schemas/fields/codecs/tagged_fields.py +109 -0
  237. kafka/protocol/schemas/fields/codecs/types.py +505 -0
  238. kafka/protocol/schemas/fields/codegen.py +40 -0
  239. kafka/protocol/schemas/fields/simple.py +127 -0
  240. kafka/protocol/schemas/fields/struct.py +357 -0
  241. kafka/protocol/schemas/fields/struct_array.py +142 -0
  242. kafka/protocol/schemas/load_json.py +42 -0
  243. kafka/protocol/schemas/resources/AddOffsetsToTxnRequest.json +40 -0
  244. kafka/protocol/schemas/resources/AddOffsetsToTxnResponse.json +35 -0
  245. kafka/protocol/schemas/resources/AddPartitionsToTxnRequest.json +65 -0
  246. kafka/protocol/schemas/resources/AddPartitionsToTxnResponse.json +60 -0
  247. kafka/protocol/schemas/resources/AlterClientQuotasRequest.json +47 -0
  248. kafka/protocol/schemas/resources/AlterClientQuotasResponse.json +41 -0
  249. kafka/protocol/schemas/resources/AlterConfigsRequest.json +43 -0
  250. kafka/protocol/schemas/resources/AlterConfigsResponse.json +39 -0
  251. kafka/protocol/schemas/resources/AlterPartitionReassignmentsRequest.json +42 -0
  252. kafka/protocol/schemas/resources/AlterPartitionReassignmentsResponse.json +47 -0
  253. kafka/protocol/schemas/resources/AlterReplicaLogDirsRequest.json +41 -0
  254. kafka/protocol/schemas/resources/AlterReplicaLogDirsResponse.json +41 -0
  255. kafka/protocol/schemas/resources/AlterUserScramCredentialsRequest.json +45 -0
  256. kafka/protocol/schemas/resources/AlterUserScramCredentialsResponse.json +35 -0
  257. kafka/protocol/schemas/resources/ApiVersionsRequest.json +34 -0
  258. kafka/protocol/schemas/resources/ApiVersionsResponse.json +79 -0
  259. kafka/protocol/schemas/resources/ConsumerProtocolAssignment.json +42 -0
  260. kafka/protocol/schemas/resources/ConsumerProtocolSubscription.json +49 -0
  261. kafka/protocol/schemas/resources/CreateAclsRequest.json +46 -0
  262. kafka/protocol/schemas/resources/CreateAclsResponse.json +37 -0
  263. kafka/protocol/schemas/resources/CreatePartitionsRequest.json +47 -0
  264. kafka/protocol/schemas/resources/CreatePartitionsResponse.json +41 -0
  265. kafka/protocol/schemas/resources/CreateTopicsRequest.json +65 -0
  266. kafka/protocol/schemas/resources/CreateTopicsResponse.json +72 -0
  267. kafka/protocol/schemas/resources/DeleteAclsRequest.json +46 -0
  268. kafka/protocol/schemas/resources/DeleteAclsResponse.json +59 -0
  269. kafka/protocol/schemas/resources/DeleteGroupsRequest.json +30 -0
  270. kafka/protocol/schemas/resources/DeleteGroupsResponse.json +36 -0
  271. kafka/protocol/schemas/resources/DeleteRecordsRequest.json +42 -0
  272. kafka/protocol/schemas/resources/DeleteRecordsResponse.json +43 -0
  273. kafka/protocol/schemas/resources/DeleteTopicsRequest.json +43 -0
  274. kafka/protocol/schemas/resources/DeleteTopicsResponse.json +52 -0
  275. kafka/protocol/schemas/resources/DescribeAclsRequest.json +43 -0
  276. kafka/protocol/schemas/resources/DescribeAclsResponse.json +55 -0
  277. kafka/protocol/schemas/resources/DescribeClientQuotasRequest.json +37 -0
  278. kafka/protocol/schemas/resources/DescribeClientQuotasResponse.json +47 -0
  279. kafka/protocol/schemas/resources/DescribeClusterRequest.json +35 -0
  280. kafka/protocol/schemas/resources/DescribeClusterResponse.json +56 -0
  281. kafka/protocol/schemas/resources/DescribeConfigsRequest.json +42 -0
  282. kafka/protocol/schemas/resources/DescribeConfigsResponse.json +69 -0
  283. kafka/protocol/schemas/resources/DescribeGroupsRequest.json +38 -0
  284. kafka/protocol/schemas/resources/DescribeGroupsResponse.json +74 -0
  285. kafka/protocol/schemas/resources/DescribeLogDirsRequest.json +38 -0
  286. kafka/protocol/schemas/resources/DescribeLogDirsResponse.json +65 -0
  287. kafka/protocol/schemas/resources/DescribeProducersRequest.json +32 -0
  288. kafka/protocol/schemas/resources/DescribeProducersResponse.json +55 -0
  289. kafka/protocol/schemas/resources/DescribeQuorumRequest.json +39 -0
  290. kafka/protocol/schemas/resources/DescribeQuorumResponse.json +82 -0
  291. kafka/protocol/schemas/resources/DescribeTopicPartitionsRequest.json +40 -0
  292. kafka/protocol/schemas/resources/DescribeTopicPartitionsResponse.json +66 -0
  293. kafka/protocol/schemas/resources/DescribeTransactionsRequest.json +27 -0
  294. kafka/protocol/schemas/resources/DescribeTransactionsResponse.json +52 -0
  295. kafka/protocol/schemas/resources/DescribeUserScramCredentialsRequest.json +30 -0
  296. kafka/protocol/schemas/resources/DescribeUserScramCredentialsResponse.json +45 -0
  297. kafka/protocol/schemas/resources/ElectLeadersRequest.json +41 -0
  298. kafka/protocol/schemas/resources/ElectLeadersResponse.json +45 -0
  299. kafka/protocol/schemas/resources/EndTxnRequest.json +43 -0
  300. kafka/protocol/schemas/resources/EndTxnResponse.json +41 -0
  301. kafka/protocol/schemas/resources/FetchRequest.json +125 -0
  302. kafka/protocol/schemas/resources/FetchResponse.json +124 -0
  303. kafka/protocol/schemas/resources/FindCoordinatorRequest.json +43 -0
  304. kafka/protocol/schemas/resources/FindCoordinatorResponse.json +58 -0
  305. kafka/protocol/schemas/resources/HeartbeatRequest.json +39 -0
  306. kafka/protocol/schemas/resources/HeartbeatResponse.json +35 -0
  307. kafka/protocol/schemas/resources/IncrementalAlterConfigsRequest.json +44 -0
  308. kafka/protocol/schemas/resources/IncrementalAlterConfigsResponse.json +38 -0
  309. kafka/protocol/schemas/resources/InitProducerIdRequest.json +50 -0
  310. kafka/protocol/schemas/resources/InitProducerIdResponse.json +47 -0
  311. kafka/protocol/schemas/resources/JoinGroupRequest.json +63 -0
  312. kafka/protocol/schemas/resources/JoinGroupResponse.json +69 -0
  313. kafka/protocol/schemas/resources/LeaveGroupRequest.json +47 -0
  314. kafka/protocol/schemas/resources/LeaveGroupResponse.json +47 -0
  315. kafka/protocol/schemas/resources/ListConfigResourcesRequest.json +31 -0
  316. kafka/protocol/schemas/resources/ListConfigResourcesResponse.json +37 -0
  317. kafka/protocol/schemas/resources/ListGroupsRequest.json +36 -0
  318. kafka/protocol/schemas/resources/ListGroupsResponse.json +49 -0
  319. kafka/protocol/schemas/resources/ListOffsetsRequest.json +72 -0
  320. kafka/protocol/schemas/resources/ListOffsetsResponse.json +71 -0
  321. kafka/protocol/schemas/resources/ListPartitionReassignmentsRequest.json +34 -0
  322. kafka/protocol/schemas/resources/ListPartitionReassignmentsResponse.json +46 -0
  323. kafka/protocol/schemas/resources/ListTransactionsRequest.json +40 -0
  324. kafka/protocol/schemas/resources/ListTransactionsResponse.json +42 -0
  325. kafka/protocol/schemas/resources/MetadataRequest.json +56 -0
  326. kafka/protocol/schemas/resources/MetadataResponse.json +101 -0
  327. kafka/protocol/schemas/resources/OffsetCommitRequest.json +76 -0
  328. kafka/protocol/schemas/resources/OffsetCommitResponse.json +71 -0
  329. kafka/protocol/schemas/resources/OffsetDeleteRequest.json +39 -0
  330. kafka/protocol/schemas/resources/OffsetDeleteResponse.json +42 -0
  331. kafka/protocol/schemas/resources/OffsetFetchRequest.json +76 -0
  332. kafka/protocol/schemas/resources/OffsetFetchResponse.json +107 -0
  333. kafka/protocol/schemas/resources/OffsetForLeaderEpochRequest.json +52 -0
  334. kafka/protocol/schemas/resources/OffsetForLeaderEpochResponse.json +51 -0
  335. kafka/protocol/schemas/resources/ProduceRequest.json +73 -0
  336. kafka/protocol/schemas/resources/ProduceResponse.json +96 -0
  337. kafka/protocol/schemas/resources/RequestHeader.json +44 -0
  338. kafka/protocol/schemas/resources/ResponseHeader.json +26 -0
  339. kafka/protocol/schemas/resources/SaslAuthenticateRequest.json +29 -0
  340. kafka/protocol/schemas/resources/SaslAuthenticateResponse.json +34 -0
  341. kafka/protocol/schemas/resources/SaslHandshakeRequest.json +31 -0
  342. kafka/protocol/schemas/resources/SaslHandshakeResponse.json +32 -0
  343. kafka/protocol/schemas/resources/SyncGroupRequest.json +56 -0
  344. kafka/protocol/schemas/resources/SyncGroupResponse.json +46 -0
  345. kafka/protocol/schemas/resources/TxnOffsetCommitRequest.json +68 -0
  346. kafka/protocol/schemas/resources/TxnOffsetCommitResponse.json +47 -0
  347. kafka/protocol/schemas/resources/UpdateFeaturesRequest.json +43 -0
  348. kafka/protocol/schemas/resources/UpdateFeaturesResponse.json +39 -0
  349. kafka/protocol/schemas/resources/WriteTxnMarkersRequest.json +49 -0
  350. kafka/protocol/schemas/resources/WriteTxnMarkersResponse.json +45 -0
  351. kafka/protocol/schemas/resources/__init__.py +0 -0
  352. kafka/record/__init__.py +3 -0
  353. kafka/record/_crc32c.py +161 -0
  354. kafka/record/abc.py +144 -0
  355. kafka/record/default_records.py +782 -0
  356. kafka/record/legacy_records.py +587 -0
  357. kafka/record/memory_records.py +255 -0
  358. kafka/record/util.py +135 -0
  359. kafka/serializer/__init__.py +4 -0
  360. kafka/serializer/abstract.py +20 -0
  361. kafka/serializer/default.py +16 -0
  362. kafka/serializer/json.py +17 -0
  363. kafka/serializer/wrapper.py +21 -0
  364. kafka/structs.py +69 -0
  365. kafka/util.py +159 -0
  366. kafka/vendor/__init__.py +0 -0
  367. kafka/version.py +1 -0
  368. kafka_python-3.0.0.dist-info/METADATA +319 -0
  369. kafka_python-3.0.0.dist-info/RECORD +373 -0
  370. kafka_python-3.0.0.dist-info/WHEEL +5 -0
  371. kafka_python-3.0.0.dist-info/entry_points.txt +2 -0
  372. kafka_python-3.0.0.dist-info/licenses/LICENSE +202 -0
  373. kafka_python-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1123 @@
1
+ import atexit
2
+ import copy
3
+ import logging
4
+ import selectors
5
+ import socket
6
+ import threading
7
+ import warnings
8
+ import weakref
9
+
10
+ import kafka.errors as Errors
11
+ from kafka.net.compat import KafkaNetClient
12
+ from kafka.codec import has_gzip, has_snappy, has_lz4, has_zstd
13
+ from kafka.metrics import MetricConfig, Metrics
14
+ from kafka.partitioner import Partitioner, DefaultPartitioner
15
+ from kafka.producer.future import FutureRecordMetadata, FutureProduceResult
16
+ from kafka.producer.record_accumulator import AtomicInteger, RecordAccumulator
17
+ from kafka.producer.sender import Sender
18
+ from kafka.producer.transaction_manager import TransactionManager
19
+ from kafka.record.default_records import DefaultRecordBatchBuilder
20
+ from kafka.record.legacy_records import LegacyRecordBatchBuilder
21
+ from kafka.serializer import Serializer, SerializeWrapper
22
+ from kafka.structs import TopicPartition
23
+ from kafka.util import Timer
24
+
25
+
26
+ log = logging.getLogger(__name__)
27
+
28
+ _LOGGED_SERIALIZE_WARNING = False
29
+
30
+ PRODUCER_CLIENT_ID_SEQUENCE = AtomicInteger()
31
+
32
+
33
+ class KafkaProducer:
34
+ """A Kafka client that publishes records to the Kafka cluster.
35
+
36
+ The producer is thread safe and sharing a single producer instance across
37
+ threads will generally be faster than having multiple instances.
38
+
39
+ The producer consists of a RecordAccumulator which holds records that
40
+ haven't yet been transmitted to the server, and a Sender background I/O
41
+ thread that is responsible for turning these records into requests and
42
+ transmitting them to the cluster.
43
+
44
+ :meth:`~kafka.KafkaProducer.send` is asynchronous. When called it adds the
45
+ record to a buffer of pending record sends and immediately returns. This
46
+ allows the producer to batch together individual records for efficiency.
47
+
48
+ The 'acks' config controls the criteria under which requests are considered
49
+ complete. The "all" setting will result in blocking on the full commit of
50
+ the record, the slowest but most durable setting.
51
+
52
+ If the request fails, the producer can automatically retry, unless
53
+ 'retries' is configured to 0. Enabling retries also opens up the
54
+ possibility of duplicates (see the documentation on message
55
+ delivery semantics for details:
56
+ https://kafka.apache.org/documentation.html#semantics
57
+ ).
58
+
59
+ The producer maintains buffers of unsent records for each partition. These
60
+ buffers are of a size specified by the 'batch_size' config. Making this
61
+ larger can result in more batching, but requires more memory (since we will
62
+ generally have one of these buffers for each active partition).
63
+
64
+ By default a buffer is available to send immediately even if there is
65
+ additional unused space in the buffer. However if you want to reduce the
66
+ number of requests you can set 'linger_ms' to something greater than 0.
67
+ This will instruct the producer to wait up to that number of milliseconds
68
+ before sending a request in hope that more records will arrive to fill up
69
+ the same batch. This is analogous to Nagle's algorithm in TCP. Note that
70
+ records that arrive close together in time will generally batch together
71
+ even with linger_ms=0 so under heavy load batching will occur regardless of
72
+ the linger configuration; however setting this to something larger than 0
73
+ can lead to fewer, more efficient requests when not under maximal load at
74
+ the cost of a small amount of latency.
75
+
76
+ The key_serializer and value_serializer instruct how to turn the key and
77
+ value objects the user provides into bytes.
78
+
79
+ From Kafka 0.11, the KafkaProducer supports two additional modes:
80
+ the idempotent producer and the transactional producer.
81
+ The idempotent producer strengthens Kafka's delivery semantics from
82
+ at least once to exactly once delivery. In particular, producer retries
83
+ will no longer introduce duplicates. The transactional producer allows an
84
+ application to send messages to multiple partitions (and topics!)
85
+ atomically.
86
+
87
+ Since KIP-679 (Kafka 3.0), idempotence is enabled by default and `acks`
88
+ defaults to 'all'. If the user explicitly provides a conflicting
89
+ `acks`, `retries=0`, or `max_in_flight_requests_per_connection > 5`, the
90
+ producer silently disables idempotence and emits a warning. Setting
91
+ `enable_idempotence=True` explicitly (or supplying `transactional_id`)
92
+ makes such conflicts raise instead. To opt out of idempotence entirely
93
+ pass `enable_idempotence=False`. There are no API changes for the
94
+ idempotent producer, so existing applications will not need to be
95
+ modified to take advantage of this feature.
96
+
97
+ To take advantage of the idempotent producer, it is imperative to avoid
98
+ application level re-sends since these cannot be de-duplicated. As such, if
99
+ an application enables idempotence, it is recommended to leave the
100
+ `retries` config unset, as it will be defaulted to `float('inf')`.
101
+ Additionally, if a :meth:`~kafka.KafkaProducer.send` returns an error even
102
+ with infinite retries (for instance if the message expires in the buffer
103
+ before being sent), then it is recommended to shut down the producer and
104
+ check the contents of the last produced message to ensure that it is not
105
+ duplicated. Finally, the producer can only guarantee idempotence for
106
+ messages sent within a single session.
107
+
108
+ To use the transactional producer and the attendant APIs, you must set the
109
+ `transactional_id` configuration property. If the `transactional_id` is
110
+ set, idempotence is automatically enabled along with the producer configs
111
+ which idempotence depends on. Further, topics which are included in
112
+ transactions should be configured for durability. In particular, the
113
+ `replication.factor` should be at least `3`, and the `min.insync.replicas`
114
+ for these topics should be set to 2. Finally, in order for transactional
115
+ guarantees to be realized from end-to-end, the consumers must be
116
+ configured to read only committed messages as well.
117
+
118
+ The purpose of the `transactional_id` is to enable transaction recovery
119
+ across multiple sessions of a single producer instance. It would typically
120
+ be derived from the shard identifier in a partitioned, stateful,
121
+ application. As such, it should be unique to each producer instance running
122
+ within a partitioned application.
123
+
124
+ Keyword Arguments:
125
+ bootstrap_servers: 'host[:port]' string (or list of 'host[:port]'
126
+ strings) that the producer should contact to bootstrap initial
127
+ cluster metadata. This does not have to be the full node list.
128
+ It just needs to have at least one broker that will respond to a
129
+ Metadata API Request. Default port is 9092. If no servers are
130
+ specified, will default to localhost:9092.
131
+ client_id (str): a name for this client. This string is passed in
132
+ each request to servers and can be used to identify specific
133
+ server-side log entries that correspond to this client.
134
+ Default: 'kafka-python-producer-#' (appended with a unique number
135
+ per instance)
136
+ key_serializer (callable): used to convert user-supplied keys to bytes
137
+ If not None, called as f(key), should return bytes. Default: None.
138
+ value_serializer (callable): used to convert user-supplied message
139
+ values to bytes. If not None, called as f(value), should return
140
+ bytes. Default: None.
141
+ transactional_id (str): Enable transactional producer with a unique
142
+ identifier. This will be used to identify the same producer
143
+ instance across process restarts. Default: None.
144
+ enable_idempotence (bool): When set to True, the producer will ensure
145
+ that exactly one copy of each message is written in the stream.
146
+ If False, producer retries due to broker failures, etc., may write
147
+ duplicates of the retried message in the stream.
148
+ Default: True (since KIP-679).
149
+
150
+ Idempotence requires `acks='all'` (-1), `retries > 0`, and
151
+ `max_in_flight_requests_per_connection <= 5`. When idempotence is
152
+ enabled by default and the user explicitly provides a conflicting
153
+ value for any of those configs, the producer silently disables
154
+ idempotence and logs a warning. When the user explicitly sets
155
+ `enable_idempotence=True` (or supplies `transactional_id`), any
156
+ such conflict raises KafkaConfigurationError instead. Requires
157
+ broker >= 0.11; against older brokers the default-driven
158
+ idempotence is silently disabled, while explicit opt-in raises.
159
+
160
+ On Kafka 2.5+ brokers, the idempotent producer automatically
161
+ recovers from transient producer-state errors (OutOfOrderSequence,
162
+ UnknownProducerId, InvalidProducerEpoch) by bumping its producer
163
+ epoch via InitProducerIdRequest v3+ (KIP-360). On older brokers,
164
+ these errors remain fatal for transactional producers and reset
165
+ the producer id for non-transactional idempotent producers.
166
+ Batches that are in-flight at the moment of a bump will have
167
+ their futures fail--their records are lost. Records still in
168
+ the accumulator (not yet drained) are produced under the bumped
169
+ epoch on the next drain.
170
+ delivery_timeout_ms (float): An upper bound on the time to report success
171
+ or failure after producer.send() returns. This limits the total time
172
+ that a record will be delayed prior to sending, the time to await
173
+ acknowledgement from the broker (if expected), and the time allowed
174
+ for retriable send failures. The producer may report failure to send
175
+ a record earlier than this config if either an unrecoverable error is
176
+ encountered, the retries have been exhausted, or the record is added
177
+ to a batch which reached an earlier delivery expiration deadline.
178
+ The value of this config should be greater than or equal to the
179
+ sum of (request_timeout_ms + linger_ms). Default: 120000.
180
+ acks (0, 1, 'all'): The number of acknowledgments the producer requires
181
+ the leader to have received before considering a request complete.
182
+ This controls the durability of records that are sent. The
183
+ following settings are common:
184
+
185
+ 0: Producer will not wait for any acknowledgment from the server.
186
+ The message will immediately be added to the socket
187
+ buffer and considered sent. No guarantee can be made that the
188
+ server has received the record in this case, and the retries
189
+ configuration will not take effect (as the client won't
190
+ generally know of any failures). The offset given back for each
191
+ record will always be set to -1.
192
+ 1: Wait for leader to write the record to its local log only.
193
+ Broker will respond without awaiting full acknowledgement from
194
+ all followers. In this case should the leader fail immediately
195
+ after acknowledging the record but before the followers have
196
+ replicated it then the record will be lost.
197
+ all: Wait for the full set of in-sync replicas to write the record.
198
+ This guarantees that the record will not be lost as long as at
199
+ least one in-sync replica remains alive. This is the strongest
200
+ available guarantee.
201
+ Default: 'all' (-1) (since KIP-679). Setting `acks` to 0 or 1
202
+ while leaving `enable_idempotence` at its default disables
203
+ idempotence silently with a warning.
204
+ compression_type (str): The compression type for all data generated by
205
+ the producer. Valid values are 'gzip', 'snappy', 'lz4', 'zstd' or None.
206
+ Compression is of full batches of data, so the efficacy of batching
207
+ will also impact the compression ratio (more batching means better
208
+ compression). Default: None.
209
+ retries (numeric): Setting a value greater than zero will cause the client
210
+ to resend any record whose send fails with a potentially transient
211
+ error. Note that this retry is no different than if the client
212
+ resent the record upon receiving the error. Allowing retries
213
+ without setting max_in_flight_requests_per_connection to 1 will
214
+ potentially change the ordering of records because if two batches
215
+ are sent to a single partition, and the first fails and is retried
216
+ but the second succeeds, then the records in the second batch may
217
+ appear first. Note additionally that produce requests will be
218
+ failed before the number of retries has been exhausted if the timeout
219
+ configured by delivery_timeout_ms expires first before successful
220
+ acknowledgement. Users should generally prefer to leave this config
221
+ unset and instead use delivery_timeout_ms to control retry behavior.
222
+ Default: float('inf') (infinite)
223
+ batch_size (int): Requests sent to brokers will contain multiple
224
+ batches, one for each partition with data available to be sent.
225
+ A small batch size will make batching less common and may reduce
226
+ throughput (a batch size of zero will disable batching entirely).
227
+ Default: 16384
228
+ linger_ms (int): The producer groups together any records that arrive
229
+ in between request transmissions into a single batched request.
230
+ Normally this occurs only under load when records arrive faster
231
+ than they can be sent out. However in some circumstances the client
232
+ may want to reduce the number of requests even under moderate load.
233
+ This setting accomplishes this by adding a small amount of
234
+ artificial delay; that is, rather than immediately sending out a
235
+ record the producer will wait for up to the given delay to allow
236
+ other records to be sent so that the sends can be batched together.
237
+ This can be thought of as analogous to Nagle's algorithm in TCP.
238
+ This setting gives the upper bound on the delay for batching: once
239
+ we get batch_size worth of records for a partition it will be sent
240
+ immediately regardless of this setting, however if we have fewer
241
+ than this many bytes accumulated for this partition we will
242
+ 'linger' for the specified time waiting for more records to show
243
+ up. This setting defaults to 0 (i.e. no delay). Setting linger_ms=5
244
+ would have the effect of reducing the number of requests sent but
245
+ would add up to 5ms of latency to records sent in the absence of
246
+ load. Default: 0.
247
+ partitioner (kafka.partitioner.Partitioner): Assigns each message
248
+ to a partition (after serialization). The default partitioner
249
+ implementation hashes each non-None serialized key using the same
250
+ algorithm as the java client (murmur2) so that messages with the
251
+ same key are assigned to the same partition.
252
+ When a key is None, the message is delivered to a random partition
253
+ (filtered to partitions with available leaders only, if possible).
254
+ Default: DefaultPartitioner().
255
+ connections_max_idle_ms: Close idle connections after the number of
256
+ milliseconds specified by this config. The broker closes idle
257
+ connections after connections.max.idle.ms, so this avoids hitting
258
+ unexpected socket disconnected errors on the client.
259
+ Default: 540000
260
+ max_block_ms (int): Number of milliseconds to block during
261
+ :meth:`~kafka.KafkaProducer.send` and
262
+ :meth:`~kafka.KafkaProducer.partitions_for`. These methods can be
263
+ blocked either because the buffer is full or metadata unavailable.
264
+ Blocking in the user-supplied serializers or partitioner will not be
265
+ counted against this timeout. Default: 60000.
266
+ max_request_size (int): The maximum size of a request. This is also
267
+ effectively a cap on the maximum record size. Note that the server
268
+ has its own cap on record size which may be different from this.
269
+ This setting will limit the number of record batches the producer
270
+ will send in a single request to avoid sending huge requests.
271
+ Default: 1048576.
272
+ allow_auto_create_topics (bool): Enable/disable auto topic creation
273
+ on metadata request. Only available with api_version >= (0, 11).
274
+ Default: True
275
+ metadata_max_age_ms (int): The period of time in milliseconds after
276
+ which we force a refresh of metadata even if we haven't seen any
277
+ partition leadership changes to proactively discover any new
278
+ brokers or partitions. Default: 300000
279
+ retry_backoff_ms (int): Milliseconds to backoff when retrying on
280
+ errors. Default: 100.
281
+ request_timeout_ms (int): Client request timeout in milliseconds.
282
+ Default: 30000.
283
+ receive_message_max_bytes (int): Maximum allowed network frame size.
284
+ Used to avoid OOM when decoding malformed network message header.
285
+ Default: 1000000.
286
+ receive_buffer_bytes (int): The size of the TCP receive buffer
287
+ (SO_RCVBUF) to use when reading data. Default: None (relies on
288
+ system defaults). Java client defaults to 32768.
289
+ send_buffer_bytes (int): The size of the TCP send buffer
290
+ (SO_SNDBUF) to use when sending data. Default: None (relies on
291
+ system defaults). Java client defaults to 131072.
292
+ socket_options (list): List of tuple-arguments to socket.setsockopt
293
+ to apply to broker connection sockets. Default:
294
+ [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]
295
+ reconnect_backoff_ms (int): The amount of time in milliseconds to
296
+ wait before attempting to reconnect to a given host.
297
+ Default: 50.
298
+ reconnect_backoff_max_ms (int): The maximum amount of time in
299
+ milliseconds to backoff/wait when reconnecting to a broker that has
300
+ repeatedly failed to connect. If provided, the backoff per host
301
+ will increase exponentially for each consecutive connection
302
+ failure, up to this maximum. Once the maximum is reached,
303
+ reconnection attempts will continue periodically with this fixed
304
+ rate. To avoid connection storms, a randomization factor of 0.2
305
+ will be applied to the backoff resulting in a random range between
306
+ 20% below and 20% above the computed value. Default: 30000.
307
+ max_in_flight_requests_per_connection (int): Requests are pipelined
308
+ to kafka brokers up to this number of maximum requests per
309
+ broker connection. Note that if this setting is set to be greater
310
+ than 1 and there are failed sends, there is a risk of message
311
+ re-ordering due to retries (i.e., if retries are enabled).
312
+ Default: 5.
313
+ security_protocol (str): Protocol used to communicate with brokers.
314
+ Valid values are: PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL.
315
+ Default: PLAINTEXT.
316
+ ssl_context (ssl.SSLContext): pre-configured SSLContext for wrapping
317
+ socket connections. If provided, all other ssl_* configurations
318
+ will be ignored. Default: None.
319
+ ssl_check_hostname (bool): flag to configure whether ssl handshake
320
+ should verify that the certificate matches the brokers hostname.
321
+ Default: True.
322
+ ssl_cafile (str): optional filename of ca file to use in certificate
323
+ verification. Default: None.
324
+ ssl_certfile (str): optional filename of file in pem format containing
325
+ the client certificate, as well as any ca certificates needed to
326
+ establish the certificate's authenticity. Default: None.
327
+ ssl_keyfile (str): optional filename containing the client private key.
328
+ Default: None.
329
+ ssl_password (str): optional password to be used when loading the
330
+ certificate chain. Default: None.
331
+ ssl_crlfile (str): optional filename containing the CRL to check for
332
+ certificate expiration. By default, no CRL check is done. When
333
+ providing a file, only the leaf certificate will be checked against
334
+ this CRL. Default: None.
335
+ ssl_ciphers (str): optionally set the available ciphers for ssl
336
+ connections. It should be a string in the OpenSSL cipher list
337
+ format. If no cipher can be selected (because compile-time options
338
+ or other configuration forbids use of all the specified ciphers),
339
+ an ssl.SSLError will be raised. See ssl.SSLContext.set_ciphers
340
+ api_version (tuple): Specify which Kafka API version to use. If set to
341
+ None, the client will infer the broker version from the results of
342
+ ApiVersionsRequest API. For brokers earlier than 0.10, which do not
343
+ support the ApiVersionsRequest API, api_version is required.
344
+ Note: Dynamic version checking is performed eagerly during __init__
345
+ and can raise KafkaTimeoutError if no connection can be made before
346
+ timeout (see bootstrap_timeout_ms below).
347
+ Different versions enable different functionality.
348
+
349
+ Examples::
350
+
351
+ (4, 3) most recent broker release, enable all supported features
352
+ (0, 11) enables message format v2 (internal)
353
+ (0, 10, 0) enables sasl authentication and message format v1
354
+ (0, 9) enables full group coordination features with automatic
355
+ partition assignment and rebalancing,
356
+ (0, 8, 2) enables kafka-storage offset commits with manual
357
+ partition assignment only,
358
+ (0, 8, 1) enables zookeeper-storage offset commits with manual
359
+ partition assignment only,
360
+ (0, 8, 0) enables basic functionality but requires manual
361
+ partition assignment and offset management.
362
+
363
+ Default: None
364
+ bootstrap_timeout_ms (int): number of milliseconds to wait for first
365
+ successful cluster bootstrap. If provided, an attempt to bootstrap
366
+ will raise KafkaTimeoutError if it is unable to fetch cluster
367
+ metadata before the configured timeout. Note that bootstrap will
368
+ be called eagerly from __init__() if api_version is None.
369
+ Default: 30000
370
+ metric_reporters (list): A list of classes to use as metrics reporters.
371
+ Implementing the AbstractMetricsReporter interface allows plugging
372
+ in classes that will be notified of new metric creation. Default: []
373
+ metrics_enabled (bool): Whether to track metrics on this instance. Default True.
374
+ metrics_num_samples (int): The number of samples maintained to compute
375
+ metrics. Default: 2
376
+ metrics_sample_window_ms (int): The maximum age in milliseconds of
377
+ samples used to compute metrics. Default: 30000
378
+ selector (selectors.BaseSelector): Provide a specific selector
379
+ implementation to use for I/O multiplexing.
380
+ Default: selectors.DefaultSelector
381
+ sasl_mechanism (str): Authentication mechanism when security_protocol
382
+ is configured for SASL_PLAINTEXT or SASL_SSL. Valid values are:
383
+ PLAIN, GSSAPI, OAUTHBEARER, SCRAM-SHA-256, SCRAM-SHA-512.
384
+ sasl_plain_username (str): username for sasl PLAIN and SCRAM authentication.
385
+ Required if sasl_mechanism is PLAIN or one of the SCRAM mechanisms.
386
+ sasl_plain_password (str): password for sasl PLAIN and SCRAM authentication.
387
+ Required if sasl_mechanism is PLAIN or one of the SCRAM mechanisms.
388
+ sasl_kerberos_name (str or gssapi.Name): Constructed gssapi.Name for use with
389
+ sasl mechanism handshake. If provided, sasl_kerberos_service_name and
390
+ sasl_kerberos_domain name are ignored. Default: None.
391
+ sasl_kerberos_service_name (str): Service name to include in GSSAPI
392
+ sasl mechanism handshake. Default: 'kafka'
393
+ sasl_kerberos_domain_name (str): kerberos domain name to use in GSSAPI
394
+ sasl mechanism handshake. Default: one of bootstrap servers
395
+ sasl_oauth_token_provider (kafka.net.sasl.oauth.AbstractTokenProvider): OAuthBearer
396
+ token provider instance. Default: None
397
+ proxy_url (str): URL to proxy socket connections through. Supports SOCKS5 only.
398
+ Requires scheme:// (e.g., socks5://foo.bar/). Default: None
399
+ kafka_client (callable): Custom class / callable for creating KafkaNetClient instances
400
+
401
+ Note:
402
+ Configuration parameters are described in more detail at
403
+ https://kafka.apache.org/0100/documentation/#producerconfigs
404
+ """
405
+ DEFAULT_CONFIG = {
406
+ 'bootstrap_servers': 'localhost',
407
+ 'client_id': None,
408
+ 'key_serializer': None,
409
+ 'value_serializer': None,
410
+ 'enable_idempotence': True,
411
+ 'transactional_id': None,
412
+ 'transaction_timeout_ms': 60000,
413
+ 'delivery_timeout_ms': 120000,
414
+ 'acks': -1,
415
+ 'compression_type': None,
416
+ 'retries': float('inf'),
417
+ 'batch_size': 16384,
418
+ 'linger_ms': 0,
419
+ 'partitioner': DefaultPartitioner(),
420
+ 'connections_max_idle_ms': 9 * 60 * 1000,
421
+ 'max_block_ms': 60000,
422
+ 'max_request_size': 1048576,
423
+ 'allow_auto_create_topics': True,
424
+ 'metadata_max_age_ms': 300000,
425
+ 'client_dns_lookup': 'use_all_dns_ips',
426
+ 'retry_backoff_ms': 100,
427
+ 'request_timeout_ms': 30000,
428
+ 'receive_message_max_bytes': 1000000,
429
+ 'receive_buffer_bytes': None,
430
+ 'send_buffer_bytes': None,
431
+ 'socket_options': [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)],
432
+ 'reconnect_backoff_ms': 50,
433
+ 'reconnect_backoff_max_ms': 30000,
434
+ 'max_in_flight_requests_per_connection': 5,
435
+ 'security_protocol': 'PLAINTEXT',
436
+ 'ssl_context': None,
437
+ 'ssl_check_hostname': True,
438
+ 'ssl_cafile': None,
439
+ 'ssl_certfile': None,
440
+ 'ssl_keyfile': None,
441
+ 'ssl_crlfile': None,
442
+ 'ssl_password': None,
443
+ 'ssl_ciphers': None,
444
+ 'api_version': None,
445
+ 'bootstrap_timeout_ms': 30000,
446
+ 'metric_reporters': [],
447
+ 'metrics_enabled': True,
448
+ 'metrics_num_samples': 2,
449
+ 'metrics_sample_window_ms': 30000,
450
+ 'selector': selectors.DefaultSelector,
451
+ 'sasl_mechanism': None,
452
+ 'sasl_plain_username': None,
453
+ 'sasl_plain_password': None,
454
+ 'sasl_kerberos_name': None,
455
+ 'sasl_kerberos_service_name': 'kafka',
456
+ 'sasl_kerberos_domain_name': None,
457
+ 'sasl_oauth_token_provider': None,
458
+ 'proxy_url': None,
459
+ 'socks5_proxy': None, # deprecated
460
+ 'kafka_client': KafkaNetClient,
461
+ }
462
+
463
+ DEPRECATED_CONFIGS = ()
464
+
465
+ _COMPRESSORS = {
466
+ 'gzip': (has_gzip, LegacyRecordBatchBuilder.CODEC_GZIP),
467
+ 'snappy': (has_snappy, LegacyRecordBatchBuilder.CODEC_SNAPPY),
468
+ 'lz4': (has_lz4, LegacyRecordBatchBuilder.CODEC_LZ4),
469
+ 'zstd': (has_zstd, DefaultRecordBatchBuilder.CODEC_ZSTD),
470
+ None: (lambda: True, LegacyRecordBatchBuilder.CODEC_NONE),
471
+ }
472
+
473
+ def __init__(self, **configs):
474
+ self.config = copy.copy(self.DEFAULT_CONFIG)
475
+ user_provided_configs = set(configs.keys())
476
+ for key in self.config:
477
+ if key in configs:
478
+ self.config[key] = configs.pop(key)
479
+
480
+ for key in ('key_serializer', 'value_serializer'):
481
+ if self.config[key] is not None and not isinstance(self.config[key], Serializer):
482
+ warnings.warn('%s does not implement kafka.serializer.Serializer' % (key,), category=DeprecationWarning, stacklevel=3)
483
+ self.config[key] = SerializeWrapper(self.config[key])
484
+
485
+ for key in self.DEPRECATED_CONFIGS:
486
+ if key in configs:
487
+ configs.pop(key)
488
+ warnings.warn('Deprecated Producer config: %s' % (key,), category=DeprecationWarning)
489
+
490
+ # Only check for extra config keys in top-level class
491
+ if configs:
492
+ raise ValueError('Unrecognized configs: %s' % (configs,))
493
+
494
+ if self.config['client_id'] is None:
495
+ self.config['client_id'] = 'kafka-python-producer-%s' % \
496
+ (PRODUCER_CLIENT_ID_SEQUENCE.increment(),)
497
+
498
+ if self.config['acks'] == 'all':
499
+ self.config['acks'] = -1
500
+
501
+ # api_version was previously a str. accept old format for now
502
+ if isinstance(self.config['api_version'], str):
503
+ deprecated = self.config['api_version']
504
+ if deprecated == 'auto':
505
+ self.config['api_version'] = None
506
+ else:
507
+ self.config['api_version'] = tuple(map(int, deprecated.split('.')))
508
+ log.warning('%s: use api_version=%s [tuple] -- "%s" as str is deprecated',
509
+ str(self), str(self.config['api_version']), deprecated)
510
+
511
+ log.debug("%s: Starting Kafka producer", str(self))
512
+
513
+ # Configure metrics
514
+ if self.config['metrics_enabled']:
515
+ metrics_tags = {'client-id': self.config['client_id']}
516
+ metric_config = MetricConfig(samples=self.config['metrics_num_samples'],
517
+ time_window_ms=self.config['metrics_sample_window_ms'],
518
+ tags=metrics_tags)
519
+ reporters = [reporter() for reporter in self.config['metric_reporters']]
520
+ self._metrics = Metrics(metric_config, reporters)
521
+ else:
522
+ self._metrics = None
523
+
524
+ client = self.config['kafka_client'](
525
+ metrics=self._metrics, metric_group_prefix='producer',
526
+ wakeup_timeout_ms=self.config['max_block_ms'],
527
+ **self.config)
528
+ manager = client._manager
529
+
530
+ # We currently depend on eager-resolution of api_version.
531
+ # If it wasn't provided as a config option, we need to bootstrap
532
+ # to get it.
533
+ if manager.broker_version_data is None:
534
+ manager.bootstrap(self.config['bootstrap_timeout_ms'])
535
+ self.config['api_version'] = manager.broker_version
536
+
537
+ if self.config['compression_type'] == 'lz4':
538
+ if self.config['api_version'] < (0, 8, 2):
539
+ raise ValueError('LZ4 Requires >= Kafka 0.8.2 Brokers')
540
+
541
+ if self.config['compression_type'] == 'zstd':
542
+ if self.config['api_version'] < (2, 1):
543
+ raise ValueError('Zstd Requires >= Kafka 2.1 Brokers')
544
+
545
+ # Check compression_type for library support
546
+ ct = self.config['compression_type']
547
+ if ct not in self._COMPRESSORS:
548
+ raise ValueError("Not supported codec: {}".format(ct))
549
+ else:
550
+ checker, compression_attrs = self._COMPRESSORS[ct]
551
+ if not checker():
552
+ raise RuntimeError("Libraries for {} compression codec not found".format(ct))
553
+ self.config['compression_attrs'] = compression_attrs
554
+
555
+ self._metadata = manager.cluster
556
+ self._transaction_manager = None
557
+ self._init_transactions_result = None
558
+
559
+ user_set_idempotence = 'enable_idempotence' in user_provided_configs
560
+ user_set_acks = 'acks' in user_provided_configs
561
+ user_set_retries = 'retries' in user_provided_configs
562
+ user_set_inflight = 'max_in_flight_requests_per_connection' in user_provided_configs
563
+
564
+ if user_set_idempotence and not self.config['enable_idempotence'] and self.config['transactional_id']:
565
+ raise Errors.KafkaConfigurationError("Cannot set transactional_id without enable_idempotence.")
566
+
567
+ if self.config['transactional_id']:
568
+ self.config['enable_idempotence'] = True
569
+ # Transactional path is strict: any conflicting user-provided config must raise.
570
+ user_set_idempotence = True
571
+
572
+ if self.config['enable_idempotence']:
573
+ conflicts = []
574
+ if user_set_acks and self.config['acks'] != -1:
575
+ conflicts.append(('acks', self.config['acks']))
576
+ if user_set_retries and self.config['retries'] == 0:
577
+ conflicts.append(('retries', 0))
578
+ if user_set_inflight and self.config['max_in_flight_requests_per_connection'] > 5:
579
+ conflicts.append(('max_in_flight_requests_per_connection',
580
+ self.config['max_in_flight_requests_per_connection']))
581
+
582
+ if conflicts:
583
+ conflict_str = ', '.join('%s=%r' % kv for kv in conflicts)
584
+ if user_set_idempotence:
585
+ raise Errors.KafkaConfigurationError(
586
+ "enable_idempotence=True is incompatible with user-provided %s" % (conflict_str,))
587
+ log.warning(
588
+ "%s: Idempotence will be disabled because user-provided config conflicts with"
589
+ " idempotent defaults: %s", str(self), conflict_str)
590
+ self.config['enable_idempotence'] = False
591
+
592
+ if self.config['enable_idempotence'] and self.config['api_version'] < (0, 11):
593
+ if user_set_idempotence:
594
+ raise Errors.KafkaConfigurationError(
595
+ "Idempotent/Transactional producer requires broker >= 0.11 (got api_version=%s)"
596
+ % (self.config['api_version'],))
597
+ log.warning(
598
+ "%s: Idempotence will be disabled because broker api_version %s < (0, 11)",
599
+ str(self), self.config['api_version'])
600
+ self.config['enable_idempotence'] = False
601
+
602
+ if self.config['enable_idempotence']:
603
+ self._transaction_manager = TransactionManager(
604
+ transactional_id=self.config['transactional_id'],
605
+ transaction_timeout_ms=self.config['transaction_timeout_ms'],
606
+ retry_backoff_ms=self.config['retry_backoff_ms'],
607
+ api_version=self.config['api_version'],
608
+ metadata=self._metadata,
609
+ )
610
+ if self._transaction_manager.is_transactional():
611
+ log.info("%s: Instantiated a transactional producer.", str(self))
612
+ else:
613
+ log.info("%s: Instantiated an idempotent producer.", str(self))
614
+
615
+ if not user_set_acks:
616
+ self.config['acks'] = -1
617
+
618
+ message_version = self.max_usable_produce_magic(self.config['api_version'])
619
+ self._accumulator = RecordAccumulator(
620
+ transaction_manager=self._transaction_manager,
621
+ message_version=message_version,
622
+ **self.config)
623
+ guarantee_message_order = False
624
+ if self.config['enable_idempotence'] or self.config['max_in_flight_requests_per_connection'] == 1:
625
+ guarantee_message_order = True
626
+ self._sender = Sender(client, self._metadata,
627
+ self._accumulator,
628
+ metrics=self._metrics,
629
+ transaction_manager=self._transaction_manager,
630
+ guarantee_message_order=guarantee_message_order,
631
+ **self.config)
632
+ self._sender.daemon = True
633
+ self._sender.start()
634
+ self._closed = False
635
+
636
+ self._cleanup = self._cleanup_factory()
637
+ atexit.register(self._cleanup)
638
+ log.debug("%s: Kafka producer started", str(self))
639
+
640
+ def bootstrap_connected(self):
641
+ """Return True if the bootstrap is connected."""
642
+ return self._sender.bootstrap_connected()
643
+
644
+ def _cleanup_factory(self):
645
+ """Build a cleanup closure that doesn't increase our ref count"""
646
+ _self = weakref.proxy(self)
647
+ def wrapper():
648
+ try:
649
+ _self.close(timeout=0, null_logger=True)
650
+ except (ReferenceError, AttributeError):
651
+ pass
652
+ return wrapper
653
+
654
+ def _unregister_cleanup(self):
655
+ if getattr(self, '_cleanup', None):
656
+ atexit.unregister(self._cleanup)
657
+ self._cleanup = None
658
+
659
+ def __del__(self):
660
+ self.close(timeout=1, null_logger=True)
661
+
662
+ def __enter__(self):
663
+ return self
664
+
665
+ def __exit__(self, exc_type, exc_val, exc_tb):
666
+ self.close()
667
+
668
+ def close(self, timeout=None, null_logger=False):
669
+ """Close this producer.
670
+
671
+ Arguments:
672
+ timeout (float, optional): timeout in seconds to wait for completion.
673
+ """
674
+ if null_logger:
675
+ # Disable logger during destruction to avoid touching dangling references
676
+ class NullLogger:
677
+ def __getattr__(self, name):
678
+ return lambda *args: None
679
+
680
+ global log
681
+ log = NullLogger()
682
+
683
+ # drop our atexit handler now to avoid leaks
684
+ self._unregister_cleanup()
685
+
686
+ if not hasattr(self, '_closed') or self._closed:
687
+ log.info('%s: Kafka producer closed', str(self))
688
+ return
689
+ if timeout is None:
690
+ timeout = threading.TIMEOUT_MAX
691
+ if not (0 <= timeout <= threading.TIMEOUT_MAX):
692
+ raise ValueError('Invalid timeout: %s' % timeout)
693
+
694
+ log.info("%s: Closing the Kafka producer with %s secs timeout.", str(self), timeout)
695
+ self.flush(timeout)
696
+ invoked_from_callback = bool(threading.current_thread() is self._sender)
697
+ if timeout > 0:
698
+ if invoked_from_callback:
699
+ log.warning("%s: Overriding close timeout %s secs to 0 in order to"
700
+ " prevent useless blocking due to self-join. This"
701
+ " means you have incorrectly invoked close with a"
702
+ " non-zero timeout from the producer call-back.",
703
+ str(self), timeout)
704
+ else:
705
+ # Try to close gracefully.
706
+ if self._sender is not None:
707
+ self._sender.initiate_close()
708
+ self._sender.join(timeout)
709
+
710
+ if self._sender is not None and self._sender.is_alive():
711
+ log.info("%s: Proceeding to force close the producer since pending"
712
+ " requests could not be completed within timeout %s.",
713
+ str(self), timeout)
714
+ self._sender.force_close()
715
+
716
+ if self._metrics:
717
+ self._metrics.close()
718
+ try:
719
+ self.config['key_serializer'].close()
720
+ except AttributeError:
721
+ pass
722
+ try:
723
+ self.config['value_serializer'].close()
724
+ except AttributeError:
725
+ pass
726
+ self._closed = True
727
+ log.debug("%s: The Kafka producer has closed.", str(self))
728
+
729
+ def partitions_for(self, topic):
730
+ """Returns set of all known partitions for the topic."""
731
+ return self._wait_on_metadata(topic, self.config['max_block_ms'])
732
+
733
+ @classmethod
734
+ def max_usable_produce_magic(cls, api_version):
735
+ if api_version >= (0, 11):
736
+ return 2
737
+ elif api_version >= (0, 10, 0):
738
+ return 1
739
+ else:
740
+ return 0
741
+
742
+ def _estimate_size_in_bytes(self, key, value, headers=None):
743
+ if headers is None:
744
+ headers = []
745
+ magic = self.max_usable_produce_magic(self.config['api_version'])
746
+ if magic == 2:
747
+ return DefaultRecordBatchBuilder.estimate_size_in_bytes(
748
+ key, value, headers)
749
+ else:
750
+ return LegacyRecordBatchBuilder.estimate_size_in_bytes(
751
+ magic, self.config['compression_type'], key, value)
752
+
753
+ def init_transactions(self):
754
+ """
755
+ Needs to be called before any other methods when the transactional.id is set in the configuration.
756
+
757
+ This method does the following:
758
+ 1. Ensures any transactions initiated by previous instances of the producer with the same
759
+ transactional_id are completed. If the previous instance had failed with a transaction in
760
+ progress, it will be aborted. If the last transaction had begun completion,
761
+ but not yet finished, this method awaits its completion.
762
+ 2. Gets the internal producer id and epoch, used in all future transactional
763
+ messages issued by the producer.
764
+
765
+ Note that this method will raise KafkaTimeoutError if the transactional state cannot
766
+ be initialized before expiration of `max_block_ms`.
767
+
768
+ Retrying after a KafkaTimeoutError will continue to wait for the prior request to succeed or fail.
769
+ Retrying after any other exception will start a new initialization attempt.
770
+ Retrying after a successful initialization will do nothing.
771
+
772
+ Raises:
773
+ IllegalStateError: if no transactional_id has been configured
774
+ AuthorizationError: fatal error indicating that the configured
775
+ transactional_id is not authorized.
776
+ KafkaError: if the producer has encountered a previous fatal error or for any other unexpected error
777
+ KafkaTimeoutError: if the time taken for initialize the transaction has surpassed `max.block.ms`.
778
+ """
779
+ if not self._transaction_manager:
780
+ raise Errors.IllegalStateError("Cannot call init_transactions without setting a transactional_id.")
781
+ if self._init_transactions_result is None:
782
+ self._init_transactions_result = self._transaction_manager.initialize_transactions()
783
+ self._sender.wakeup()
784
+
785
+ try:
786
+ if not self._init_transactions_result.wait(timeout_ms=self.config['max_block_ms']):
787
+ raise Errors.KafkaTimeoutError("Timeout expired while initializing transactional state in %s ms." % (self.config['max_block_ms'],))
788
+ finally:
789
+ if self._init_transactions_result.failed:
790
+ self._init_transactions_result = None
791
+
792
+ def begin_transaction(self):
793
+ """ Should be called before the start of each new transaction.
794
+
795
+ Note that prior to the first invocation of this method,
796
+ you must invoke `init_transactions()` exactly one time.
797
+
798
+ Raises:
799
+ ProducerFencedError if another producer is with the same
800
+ transactional_id is active.
801
+ """
802
+ # Set the transactional bit in the producer.
803
+ if not self._transaction_manager:
804
+ raise Errors.IllegalStateError("Cannot use transactional methods without enabling transactions")
805
+ self._transaction_manager.begin_transaction()
806
+
807
+ def send_offsets_to_transaction(self, offsets, group_metadata):
808
+ """
809
+ Sends a list of consumed offsets to the consumer group coordinator, and also marks
810
+ those offsets as part of the current transaction. These offsets will be considered
811
+ consumed only if the transaction is committed successfully.
812
+
813
+ This method should be used when you need to batch consumed and produced messages
814
+ together, typically in a consume-transform-produce pattern.
815
+
816
+ Arguments:
817
+ offsets ({TopicPartition: OffsetAndMetadata}): map of topic-partition -> offsets to commit
818
+ as part of current transaction.
819
+ group_metadata (ConsumerGroupMetadata or str): full group metadata from
820
+ KafkaConsumer.group_metadata() (preferred - enables broker-side fencing
821
+ of stale consumer instances per KIP-447 against Kafka 2.5+ brokers), or
822
+ a bare consumer_group_id str for backwards compatibility.
823
+
824
+ Raises:
825
+ IllegalStateError: if no transactional_id, or transaction has not been started.
826
+ ProducerFencedError: fatal error indicating another producer with the same transactional_id is active.
827
+ UnsupportedVersionError: fatal error indicating the broker does not support transactions (i.e. if < 0.11).
828
+ UnsupportedForMessageFormatError: fatal error indicating the message format used for the offsets
829
+ topic on the broker does not support transactions.
830
+ AuthorizationError: fatal error indicating that the configured transactional_id is not authorized.
831
+ KafkaErro:r if the producer has encountered a previous fatal or abortable error, or for any
832
+ other unexpected error
833
+ """
834
+ if not self._transaction_manager:
835
+ raise Errors.IllegalStateError("Cannot use transactional methods without enabling transactions")
836
+ result = self._transaction_manager.send_offsets_to_transaction(offsets, group_metadata)
837
+ self._sender.wakeup()
838
+ result.wait()
839
+
840
+ def commit_transaction(self):
841
+ """ Commits the ongoing transaction.
842
+
843
+ Raises: ProducerFencedError if another producer with the same
844
+ transactional_id is active.
845
+ """
846
+ if not self._transaction_manager:
847
+ raise Errors.IllegalStateError("Cannot commit transaction since transactions are not enabled")
848
+ result = self._transaction_manager.begin_commit()
849
+ self._sender.wakeup()
850
+ result.wait()
851
+
852
+ def abort_transaction(self):
853
+ """ Aborts the ongoing transaction.
854
+
855
+ Raises: ProducerFencedError if another producer with the same
856
+ transactional_id is active.
857
+ """
858
+ if not self._transaction_manager:
859
+ raise Errors.IllegalStateError("Cannot abort transaction since transactions are not enabled.")
860
+ result = self._transaction_manager.begin_abort()
861
+ self._sender.wakeup()
862
+ result.wait()
863
+
864
+ def send(self, topic, value=None, key=None, headers=None, partition=None, timestamp_ms=None):
865
+ """Publish a message to a topic.
866
+
867
+ Arguments:
868
+ topic (str): topic where the message will be published
869
+ value (optional): message value. Must be type bytes, or be
870
+ serializable to bytes via configured value_serializer. If value
871
+ is None, key is required and message acts as a 'delete'.
872
+ See kafka compaction documentation for more details:
873
+ https://kafka.apache.org/documentation.html#compaction
874
+ (compaction requires kafka >= 0.8.1)
875
+ partition (int, optional): optionally specify a partition. If not
876
+ set, the partition will be selected using the configured
877
+ 'partitioner'.
878
+ key (optional): a key to associate with the message. Can be used to
879
+ determine which partition to send the message to. If partition
880
+ is None (and producer's partitioner config is left as default),
881
+ then messages with the same key will be delivered to the same
882
+ partition (but if key is None, partition is chosen randomly).
883
+ Must be type bytes, or be serializable to bytes via configured
884
+ key_serializer.
885
+ headers (optional): a list of header key value pairs. List items
886
+ are tuples of str key and bytes value.
887
+ timestamp_ms (int, optional): epoch milliseconds (from Jan 1 1970 UTC)
888
+ to use as the message timestamp. Defaults to current time.
889
+
890
+ Returns:
891
+ FutureRecordMetadata: resolves to RecordMetadata
892
+
893
+ Raises:
894
+ KafkaTimeoutError: if unable to fetch topic metadata, or unable
895
+ to obtain memory buffer prior to configured max_block_ms.
896
+ TypeError: if topic is not a string; if serialized key/value
897
+ are not type bytes/bytearray/memoryview or None; or headers
898
+ is not a list of (str, bytes) items.
899
+ ValueError: if both key and value are None; partitioner fails to
900
+ assign a partition, or topic is invalid (must be chars
901
+ [a-zA-Z0-9._-], and less than 250 length).
902
+ IllegalStateError: if KafkaProducer is already closed.
903
+ """
904
+ if self._closed:
905
+ raise Errors.IllegalStateError('KafkaProducer already closed!')
906
+ if value is None and self.config['api_version'] < (0, 8, 1):
907
+ raise ValueError('Null messages require kafka >= 0.8.1')
908
+ if value is None and key is None:
909
+ raise ValueError('Need at least one: key or value')
910
+ if headers is None:
911
+ headers = []
912
+ if not isinstance(headers, list):
913
+ raise TypeError('headers must be list-type')
914
+ if not all(isinstance(item, tuple) and len(item) == 2 and isinstance(item[0], str) and isinstance(item[1], bytes) for item in headers):
915
+ raise TypeError('All headers items must be (str, bytes) tuples')
916
+
917
+ key_bytes = self._serialize(
918
+ self.config['key_serializer'],
919
+ topic, headers, key)
920
+ value_bytes = self._serialize(
921
+ self.config['value_serializer'],
922
+ topic, headers, value)
923
+ if type(key_bytes) not in (bytes, bytearray, memoryview, type(None)):
924
+ raise TypeError("Unsupported type for serialized key: %s" % type(key_bytes))
925
+ if type(value_bytes) not in (bytes, bytearray, memoryview, type(None)):
926
+ raise TypeError("Unsupported type for serialized value: %s" % type(value_bytes))
927
+
928
+ if self._metadata.partitions_for_topic(topic) is None:
929
+ try:
930
+ self._wait_on_metadata(topic, self.config['max_block_ms'])
931
+ except Errors.BrokerResponseError as e:
932
+ log.error("%s: Exception occurred waiting for metadata during message send: %s", str(self), e)
933
+ return FutureRecordMetadata(
934
+ FutureProduceResult(TopicPartition(topic, partition)),
935
+ -1, None, None,
936
+ len(key_bytes) if key_bytes is not None else -1,
937
+ len(value_bytes) if value_bytes is not None else -1,
938
+ sum(len(h_key.encode("utf-8")) + len(h_value) for h_key, h_value in headers) if headers else -1,
939
+ ).failure(e)
940
+
941
+ # Track if the user passed an explicit partition b/c sticky logic does not apply
942
+ explicit_partition = partition is not None
943
+ partition = self._partition(topic, partition, key, value, key_bytes, value_bytes)
944
+ if partition is None:
945
+ raise ValueError(f'Partitioner did not assign a partition for topic {topic}!')
946
+
947
+ message_size = self._estimate_size_in_bytes(key_bytes, value_bytes, headers)
948
+ self._ensure_valid_record_size(message_size)
949
+
950
+ tp = TopicPartition(topic, partition)
951
+ log.debug("%s: Sending (key=%r value=%r headers=%r) to %s", str(self), key, value, headers, tp)
952
+
953
+ if self._transaction_manager and self._transaction_manager.is_transactional():
954
+ self._transaction_manager.maybe_add_partition_to_transaction(tp)
955
+
956
+ # KIP-480: when sticky-aware partitioning is in play (no explicit
957
+ # partition, no key), try once with abort_on_new_batch=True. If the
958
+ # accumulator would have to allocate a fresh batch for this partition,
959
+ # rotate the sticky partition first and re-pick. The record that
960
+ # *triggers* the new batch then lands on the rotated partition, not
961
+ # the next one.
962
+ sticky_eligible = not explicit_partition and key_bytes is None
963
+ result = self._accumulator.append(tp, timestamp_ms, key_bytes, value_bytes, headers,
964
+ abort_on_new_batch=sticky_eligible)
965
+ future, batch_is_full, new_batch_created, abort_for_new_batch = result
966
+ if abort_for_new_batch:
967
+ prev_partition = partition
968
+ on_new_batch = getattr(self.config['partitioner'], 'on_new_batch', None)
969
+ if on_new_batch is not None:
970
+ on_new_batch(topic, self._metadata, prev_partition)
971
+ # Re-pick - sticky cache may now point at a different partition.
972
+ partition = self._partition(topic, None, key, value, key_bytes, value_bytes)
973
+ tp = TopicPartition(topic, partition)
974
+ if self._transaction_manager and self._transaction_manager.is_transactional():
975
+ self._transaction_manager.maybe_add_partition_to_transaction(tp)
976
+ result = self._accumulator.append(tp, timestamp_ms, key_bytes, value_bytes, headers,
977
+ abort_on_new_batch=False)
978
+ future, batch_is_full, new_batch_created, _ = result
979
+
980
+ if batch_is_full or new_batch_created:
981
+ log.debug("%s: Waking up the sender since %s is either full or"
982
+ " getting a new batch", str(self), tp)
983
+ self._sender.wakeup()
984
+ return future
985
+
986
+ def flush(self, timeout=None):
987
+ """
988
+ Invoking this method makes all buffered records immediately available
989
+ to send (even if linger_ms is greater than 0) and blocks on the
990
+ completion of the requests associated with these records. The
991
+ post-condition of :meth:`~kafka.KafkaProducer.flush` is that any
992
+ previously sent record will have completed
993
+ (e.g. Future.is_done() == True). A request is considered completed when
994
+ either it is successfully acknowledged according to the 'acks'
995
+ configuration for the producer, or it results in an error.
996
+
997
+ Other threads can continue sending messages while one thread is blocked
998
+ waiting for a flush call to complete; however, no guarantee is made
999
+ about the completion of messages sent after the flush call begins.
1000
+
1001
+ Arguments:
1002
+ timeout (float, optional): timeout in seconds to wait for completion.
1003
+
1004
+ Raises:
1005
+ KafkaTimeoutError: failure to flush buffered records within the
1006
+ provided timeout
1007
+ """
1008
+ log.debug("%s: Flushing accumulated records in producer.", str(self))
1009
+ self._accumulator.begin_flush()
1010
+ self._sender.wakeup()
1011
+ self._accumulator.await_flush_completion(timeout=timeout)
1012
+
1013
+ def _ensure_valid_record_size(self, size):
1014
+ """Validate that the record size isn't too large."""
1015
+ if size > self.config['max_request_size']:
1016
+ raise Errors.MessageSizeTooLargeError(
1017
+ "The message is %d bytes when serialized which is larger than"
1018
+ " the maximum request size you have configured with the"
1019
+ " max_request_size configuration" % (size,))
1020
+
1021
+ def _wait_on_metadata(self, topic, max_wait_ms):
1022
+ """
1023
+ Wait for cluster metadata including partitions for the given topic to
1024
+ be available.
1025
+
1026
+ Arguments:
1027
+ topic (str): topic we want metadata for
1028
+ max_wait (float): maximum time in secs for waiting on the metadata
1029
+
1030
+ Returns:
1031
+ set: partition ids for the topic
1032
+
1033
+ Raises:
1034
+ KafkaTimeoutError: if partitions for topic were not obtained before
1035
+ specified max_wait timeout
1036
+ TopicAuthorizationFailedError: if not authorized to access topic
1037
+ Non-retriable errors that cause metadata refresh to fail
1038
+ """
1039
+ partitions = self._metadata.partitions_for_topic(topic)
1040
+ if partitions is not None:
1041
+ return partitions
1042
+ self._sender.add_topic(topic)
1043
+ timer = Timer(max_wait_ms)
1044
+ metadata_event = threading.Event()
1045
+ while not timer.expired:
1046
+ log.debug("%s: Requesting metadata update for topic %s", str(self), topic)
1047
+ metadata_event.clear()
1048
+ future = self._metadata.request_update()
1049
+ future.add_both(lambda e, *args: e.set(), metadata_event)
1050
+ self._sender.wakeup()
1051
+ metadata_event.wait(timer.timeout_ms / 1000)
1052
+ if not future.is_done:
1053
+ raise Errors.KafkaTimeoutError(
1054
+ "Failed to update metadata after %.1f secs." % (max_wait_ms / 1000,))
1055
+ elif future.failed() and not future.retriable():
1056
+ raise future.exception
1057
+ elif topic in self._metadata.unauthorized_topics:
1058
+ raise Errors.TopicAuthorizationFailedError(set([topic]))
1059
+ else:
1060
+ log.debug("%s: _wait_on_metadata woke after %s secs.", str(self), timer.elapsed_ms / 1000)
1061
+ partitions = self._metadata.partitions_for_topic(topic)
1062
+ if partitions is not None:
1063
+ return partitions
1064
+ else:
1065
+ raise Errors.KafkaTimeoutError("Failed to update metadata after %.1f secs." % (max_wait_ms / 1000,))
1066
+
1067
+ def _serialize(self, serializer, topic, headers, data):
1068
+ if serializer is None:
1069
+ return data
1070
+ try:
1071
+ return serializer.serialize(topic, headers, data)
1072
+ except TypeError:
1073
+ global _LOGGED_SERIALIZE_WARNING
1074
+ if not _LOGGED_SERIALIZE_WARNING:
1075
+ warnings.warn('serializer does not implement serialize(topic, headers, data)', category=DeprecationWarning)
1076
+ LOGGED_SERIALIZE_WARNING = True
1077
+ return serializer.serialize(topic, data)
1078
+
1079
+ def _partition(self, topic, partition, key, value,
1080
+ serialized_key, serialized_value):
1081
+ if topic not in self._metadata.topics():
1082
+ return None
1083
+ if partition is not None:
1084
+ if partition < 0:
1085
+ raise ValueError('partition must be >= 0')
1086
+ all_partitions = self._metadata.partitions_for_topic(topic)
1087
+ if all_partitions is None or partition not in all_partitions:
1088
+ raise ValueError('Unrecognized partition %s for topic %s' % (partition, topic))
1089
+ return partition
1090
+
1091
+ partitioner = self.config['partitioner']
1092
+ if not isinstance(partitioner, Partitioner):
1093
+ warnings.warn('partitioner does not implement kafka.partitioner.Partitioner', category=DeprecationWarning)
1094
+ return partitioner.partition(topic, serialized_key, self._metadata)
1095
+ return partitioner.partition(
1096
+ topic, key, serialized_key, value, serialized_value, self._metadata)
1097
+
1098
+ def metrics(self, raw=False):
1099
+ """Get metrics on producer performance.
1100
+
1101
+ This is ported from the Java Producer, for details see:
1102
+ https://kafka.apache.org/documentation/#producer_monitoring
1103
+
1104
+ Warning:
1105
+ This is an unstable interface. It may change in future
1106
+ releases without warning.
1107
+ """
1108
+ if not self._metrics:
1109
+ return
1110
+ if raw:
1111
+ return self._metrics.metrics.copy()
1112
+
1113
+ metrics = {}
1114
+ for k, v in self._metrics.metrics.copy().items():
1115
+ if k.group not in metrics:
1116
+ metrics[k.group] = {}
1117
+ if k.name not in metrics[k.group]:
1118
+ metrics[k.group][k.name] = {}
1119
+ metrics[k.group][k.name] = v.value()
1120
+ return metrics
1121
+
1122
+ def __str__(self):
1123
+ return "<KafkaProducer client_id=%s transactional_id=%s>" % (self.config.get('client_id', None), self.config.get('transactional_id', None))