Перейти к основному содержимому
Эта страница ещё не переведена

Ниже показан английский оригинал.

Keys

The partition-key header, PARTITION_KEY_HEADER, becomes the record's native key, so records sharing a key land on one partition, in order.

The header is named kafka-partition-key. On publish its value becomes the Kafka record key and does not travel as a header of its own. Kafka's partitioner hashes the key, so every record of one key goes to one partition, and a consumer reads them in the order they were written. A message type declares the header in its typed header contract, #[outgoing(headers = ..)], with a field renamed to kafka-partition-key; a HeaderMap with that entry works the same. On consume the header holds the record key again, and a handler reads the key as raw bytes through the Key context key. workers(n, by_key) with LaneKey::RecordKey keeps the same order inside one consumer: records of one key run on one lane. A partition step places a record ahead of its key.

Example​

/// The header a shipment carries: `kafka-partition-key`, which becomes the record key.
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct ShipmentKey {
#[serde(rename = "kafka-partition-key")]
customer: String,
}

/// Every shipment of one customer lands on one partition, so its consumer sees them in order.
#[derive(Debug, PartialEq, Deserialize, Serialize, Outgoing)]
#[outgoing(name = "shipments", headers = ShipmentKey)]
struct Shipment {
order_id: u64,
}

#[derive(OutSlot)]
#[publishes(Shipment)]
struct Shipments;

#[subscriber(KafkaTopic::new("orders").group("shipping"))]
async fn ship(order: &Order, Out(shipments): Out<impl Publisher, Shipments>) -> HandlerOutcome {
let key = ShipmentKey {
customer: order.customer.clone(),
};
let shipment = Shipment { order_id: order.id };
if shipments
.message(&shipment)
.with_headers(&key)
.publish()
.await
.is_err()
{
return HandlerOutcome::retry();
}
HandlerOutcome::ack()
}