Skip to content

BatchPublisher

faststream.kafka.publisher.BatchPublisher #

BatchPublisher(
    config: KafkaPublisherConfig,
    specification: PublisherSpecification[Any, Any],
)

Bases: LogicPublisher

Source code in faststream/kafka/publisher/usecase.py
311
312
313
314
315
316
317
def __init__(
    self,
    config: "KafkaPublisherConfig",
    specification: "PublisherSpecification[Any, Any]",
) -> None:
    super().__init__(config, specification)
    self.key = config.key

is_test instance-attribute #

is_test = False

mock property #

mock: MagicMock

The mock recording the endpoint's calls, available under a test broker.

specification instance-attribute #

specification = specification

partition instance-attribute #

partition = config.partition

reply_to instance-attribute #

reply_to = config.reply_to

headers instance-attribute #

headers = config.headers or {}

topic property #

topic: str

key instance-attribute #

key = config.key

request async #

request(
    message: SendableMessage,
    topic: str = "",
    *,
    key: bytes | Any | None = None,
    partition: int | None = None,
    timestamp_ms: int | None = None,
    headers: dict[str, str] | None = None,
    correlation_id: str | None = None,
    timeout: float = 0.5,
) -> KafkaMessage

Send a request message to Kafka topic.

PARAMETER DESCRIPTION
message

Message body to send.

TYPE: SendableMessage

topic

Topic where the message will be published.

TYPE: str DEFAULT: ''

key

A key to associate with the message. Can be used to determine which partition to send the message to. If partition is None (and producer's partitioner config is left as default), then messages with the same key will be delivered to the same partition (but if key is None, partition is chosen randomly). Must be type bytes, or be serializable to bytes via configured key_serializer.

TYPE: bytes | Any | None DEFAULT: None

partition

Specify a partition. If not set, the partition will be selected using the configured partitioner.

TYPE: int | None DEFAULT: None

timestamp_ms

Epoch milliseconds (from Jan 1 1970 UTC) to use as the message timestamp. Defaults to current time.

TYPE: int | None DEFAULT: None

headers

Message headers to store metainformation.

TYPE: dict[str, str] | None DEFAULT: None

correlation_id

Manual message correlation_id setter. correlation_id is a useful option to trace messages.

TYPE: str | None DEFAULT: None

timeout

Timeout to send RPC request.

TYPE: float DEFAULT: 0.5

RETURNS DESCRIPTION
KafkaMessage

The response message.

TYPE: KafkaMessage

Source code in faststream/kafka/publisher/usecase.py
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
@override
async def request(
    self,
    message: "SendableMessage",
    topic: str = "",
    *,
    key: bytes | Any | None = None,
    partition: int | None = None,
    timestamp_ms: int | None = None,
    headers: dict[str, str] | None = None,
    correlation_id: str | None = None,
    timeout: float = 0.5,
) -> "KafkaMessage":
    """Send a request message to Kafka topic.

    Args:
        message: Message body to send.
        topic: Topic where the message will be published.
        key: A key to associate with the message. Can be used to
            determine which partition to send the message to. If partition
            is `None` (and producer's partitioner config is left as default),
            then messages with the same key will be delivered to the same
            partition (but if key is `None`, partition is chosen randomly).
            Must be type `bytes`, or be serializable to bytes via configured
            `key_serializer`.
        partition: Specify a partition. If not set, the partition will be
            selected using the configured `partitioner`.
        timestamp_ms: Epoch milliseconds (from Jan 1 1970 UTC) to use as
            the message timestamp. Defaults to current time.
        headers: Message headers to store metainformation.
        correlation_id: Manual message **correlation_id** setter.
            **correlation_id** is a useful option to trace messages.
        timeout: Timeout to send RPC request.

    Returns:
        KafkaMessage: The response message.
    """
    cmd = KafkaPublishCommand(
        message,
        topic=topic or self.topic,
        key=key,
        partition=partition if partition is not None else self.partition,
        headers=self.headers | (headers or {}),
        correlation_id=correlation_id or self._outer_config.id_generator(),
        timestamp_ms=timestamp_ms,
        timeout=timeout,
        _publish_type=PublishType.REQUEST,
    )

    msg: KafkaMessage = await self._basic_request(
        cmd,
        producer=self._outer_config.producer,
    )
    return msg

assert_called_once_with async #

assert_called_once_with(
    body: Any = EMPTY,
    /,
    *,
    headers: Any = EMPTY,
    correlation_id: Any = EMPTY,
    reply_to: Any = EMPTY,
    content_type: Any = EMPTY,
    path: Any = EMPTY,
    context: Mapping[str, Any] = EMPTY,
) -> None

Assert the endpoint was called once, with the message described here.

PARAMETER DESCRIPTION
body

The body as a dict, a model or a matcher; it goes through the codec.

TYPE: Any DEFAULT: EMPTY

headers

Headers the message must carry; the rest may carry more.

TYPE: Any DEFAULT: EMPTY

correlation_id

The exact correlation id.

TYPE: Any DEFAULT: EMPTY

reply_to

The exact reply-to destination.

TYPE: Any DEFAULT: EMPTY

content_type

The exact content type.

TYPE: Any DEFAULT: EMPTY

path

The exact path parameters the subject template matched.

TYPE: Any DEFAULT: EMPTY

context

Context paths, as given to Context(), mapped to their values.

TYPE: Mapping[str, Any] DEFAULT: EMPTY

Source code in faststream/_internal/testing/calls.py
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
async def assert_called_once_with(
    self,
    body: Any = EMPTY,
    /,
    *,
    headers: Any = EMPTY,
    correlation_id: Any = EMPTY,
    reply_to: Any = EMPTY,
    content_type: Any = EMPTY,
    path: Any = EMPTY,
    context: Mapping[str, Any] = EMPTY,
) -> None:
    """Assert the endpoint was called once, with the message described here.

    Args:
        body: The body as a dict, a model or a matcher; it goes through the codec.
        headers: Headers the message must carry; the rest may carry more.
        correlation_id: The exact correlation id.
        reply_to: The exact reply-to destination.
        content_type: The exact content type.
        path: The exact path parameters the subject template matched.
        context: Context paths, as given to `Context()`, mapped to their values.
    """
    recorder = self._recorder_with_calls()
    recorder.mock.assert_called_once()
    await recorder.assert_last_call(
        ExpectedCall(
            body=body,
            headers=headers,
            correlation_id=correlation_id,
            reply_to=reply_to,
            content_type=content_type,
            path=path,
            context=context,
        )
    )

assert_called_with async #

assert_called_with(
    body: Any = EMPTY,
    /,
    *,
    headers: Any = EMPTY,
    correlation_id: Any = EMPTY,
    reply_to: Any = EMPTY,
    content_type: Any = EMPTY,
    path: Any = EMPTY,
    context: Mapping[str, Any] = EMPTY,
) -> None

Assert the last message the endpoint saw is the one described here.

PARAMETER DESCRIPTION
body

The body as a dict, a model or a matcher; it goes through the codec.

TYPE: Any DEFAULT: EMPTY

headers

Headers the message must carry; the rest may carry more.

TYPE: Any DEFAULT: EMPTY

correlation_id

The exact correlation id.

TYPE: Any DEFAULT: EMPTY

reply_to

The exact reply-to destination.

TYPE: Any DEFAULT: EMPTY

content_type

The exact content type.

TYPE: Any DEFAULT: EMPTY

path

The exact path parameters the subject template matched.

TYPE: Any DEFAULT: EMPTY

context

Context paths, as given to Context(), mapped to their values.

TYPE: Mapping[str, Any] DEFAULT: EMPTY

Source code in faststream/_internal/testing/calls.py
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
async def assert_called_with(
    self,
    body: Any = EMPTY,
    /,
    *,
    headers: Any = EMPTY,
    correlation_id: Any = EMPTY,
    reply_to: Any = EMPTY,
    content_type: Any = EMPTY,
    path: Any = EMPTY,
    context: Mapping[str, Any] = EMPTY,
) -> None:
    """Assert the last message the endpoint saw is the one described here.

    Args:
        body: The body as a dict, a model or a matcher; it goes through the codec.
        headers: Headers the message must carry; the rest may carry more.
        correlation_id: The exact correlation id.
        reply_to: The exact reply-to destination.
        content_type: The exact content type.
        path: The exact path parameters the subject template matched.
        context: Context paths, as given to `Context()`, mapped to their values.
    """
    recorder = self._recorder_with_calls()
    await recorder.assert_last_call(
        ExpectedCall(
            body=body,
            headers=headers,
            correlation_id=correlation_id,
            reply_to=reply_to,
            content_type=content_type,
            path=path,
            context=context,
        )
    )

assert_any_call async #

assert_any_call(
    body: Any = EMPTY,
    /,
    *,
    headers: Any = EMPTY,
    correlation_id: Any = EMPTY,
    reply_to: Any = EMPTY,
    content_type: Any = EMPTY,
    path: Any = EMPTY,
    context: Mapping[str, Any] = EMPTY,
) -> None

Assert one of the messages the endpoint saw is the one described here.

PARAMETER DESCRIPTION
body

The body as a dict, a model or a matcher; it goes through the codec.

TYPE: Any DEFAULT: EMPTY

headers

Headers the message must carry; the rest may carry more.

TYPE: Any DEFAULT: EMPTY

correlation_id

The exact correlation id.

TYPE: Any DEFAULT: EMPTY

reply_to

The exact reply-to destination.

TYPE: Any DEFAULT: EMPTY

content_type

The exact content type.

TYPE: Any DEFAULT: EMPTY

path

The exact path parameters the subject template matched.

TYPE: Any DEFAULT: EMPTY

context

Context paths, as given to Context(), mapped to their values.

TYPE: Mapping[str, Any] DEFAULT: EMPTY

Source code in faststream/_internal/testing/calls.py
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
async def assert_any_call(
    self,
    body: Any = EMPTY,
    /,
    *,
    headers: Any = EMPTY,
    correlation_id: Any = EMPTY,
    reply_to: Any = EMPTY,
    content_type: Any = EMPTY,
    path: Any = EMPTY,
    context: Mapping[str, Any] = EMPTY,
) -> None:
    """Assert one of the messages the endpoint saw is the one described here.

    Args:
        body: The body as a dict, a model or a matcher; it goes through the codec.
        headers: Headers the message must carry; the rest may carry more.
        correlation_id: The exact correlation id.
        reply_to: The exact reply-to destination.
        content_type: The exact content type.
        path: The exact path parameters the subject template matched.
        context: Context paths, as given to `Context()`, mapped to their values.
    """
    recorder = self._recorder_with_calls()
    await recorder.assert_any_call(
        ExpectedCall(
            body=body,
            headers=headers,
            correlation_id=correlation_id,
            reply_to=reply_to,
            content_type=content_type,
            path=path,
            context=context,
        )
    )

start async #

start() -> None
Source code in faststream/_internal/endpoint/publisher/usecase.py
57
58
async def start(self) -> None:
    pass

set_test #

set_test(
    *, recorder: CallRecorder | None = None, with_fake: bool
) -> None

Turn publisher to testing mode, sharing recorder when one is given.

Source code in faststream/_internal/endpoint/publisher/usecase.py
60
61
62
63
64
65
66
67
68
69
70
71
72
def set_test(
    self,
    *,
    recorder: CallRecorder | None = None,
    with_fake: bool,
) -> None:
    """Turn publisher to testing mode, sharing `recorder` when one is given."""
    self.is_test = True
    if recorder is None:
        self._recorder.reset()
    else:
        self._recorder = recorder
    self._fake_handler = with_fake

reset_test #

reset_test() -> None

Turn off publisher's testing mode.

Source code in faststream/_internal/endpoint/publisher/usecase.py
74
75
76
77
78
79
80
def reset_test(self) -> None:
    """Turn off publisher's testing mode."""
    self.is_test = False
    self._recorder.reset()
    # A shared recorder goes back to the handler it belongs to
    self._recorder = CallRecorder(self.specification.name, self._outer_config)
    self._fake_handler = False

schema #

schema() -> dict[str, PublisherSpec]
Source code in faststream/_internal/endpoint/publisher/usecase.py
157
158
def schema(self) -> dict[str, "PublisherSpec"]:
    return self.specification.get_schema()

flush async #

flush() -> None
Source code in faststream/kafka/publisher/usecase.py
107
108
109
async def flush(self) -> None:
    producer = cast("AioKafkaFastProducer", self._outer_config.producer)
    await producer.flush()

publish async #

publish(
    *messages: KafkaSendableMessage,
    topic: str = "",
    key: bytes | Any | None = None,
    partition: int | None = None,
    timestamp_ms: int | None = None,
    headers: dict[str, str] | None = None,
    reply_to: str = "",
    correlation_id: str | None = None,
    no_confirm: Literal[False] = False,
) -> RecordMetadata
publish(
    *messages: KafkaSendableMessage,
    topic: str = "",
    key: bytes | Any | None = None,
    partition: int | None = None,
    timestamp_ms: int | None = None,
    headers: dict[str, str] | None = None,
    reply_to: str = "",
    correlation_id: str | None = None,
    no_confirm: Literal[True] = ...,
) -> Future[RecordMetadata]
publish(
    *messages: KafkaSendableMessage,
    topic: str = "",
    key: bytes | Any | None = None,
    partition: int | None = None,
    timestamp_ms: int | None = None,
    headers: dict[str, str] | None = None,
    reply_to: str = "",
    correlation_id: str | None = None,
    no_confirm: bool = False,
) -> Union[Future[RecordMetadata], RecordMetadata]
publish(
    *messages: KafkaSendableMessage,
    topic: str = "",
    key: bytes | Any | None = None,
    partition: int | None = None,
    timestamp_ms: int | None = None,
    headers: dict[str, str] | None = None,
    reply_to: str = "",
    correlation_id: str | None = None,
    no_confirm: bool = False,
) -> Union[Future[RecordMetadata], RecordMetadata]

Publish a message batch as a single request to broker.

PARAMETER DESCRIPTION
*messages

Messages bodies to send.

TYPE: KafkaSendableMessage DEFAULT: ()

topic

Topic where the message will be published.

TYPE: str DEFAULT: ''

key

A single key to associate with every message in this batch. If a partition is not specified and the producer uses the default partitioner, messages with the same key will be routed to the same partition. Must be bytes or serializable to bytes via the configured key serializer. If omitted, falls back to the publisher's default key (if configured).

TYPE: bytes | Any | None DEFAULT: None

partition

Specify a partition. If not set, the partition will be selected using the configured partitioner

TYPE: int | None DEFAULT: None

timestamp_ms

Epoch milliseconds (from Jan 1 1970 UTC) to use as the message timestamp. Defaults to current time.

TYPE: int | None DEFAULT: None

headers

Message headers to store metainformation.

TYPE: dict[str, str] | None DEFAULT: None

reply_to

Reply message topic name to send response.

TYPE: str DEFAULT: ''

correlation_id

Manual message correlation_id setter. correlation_id is a useful option to trace messages.

TYPE: str | None DEFAULT: None

no_confirm

Do not wait for Kafka publish confirmation.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
Union[Future[RecordMetadata], RecordMetadata]

asyncio.Future[RecordMetadata] if no_confirm = True.

Union[Future[RecordMetadata], RecordMetadata]

RecordMetadata if no_confirm = False.

Source code in faststream/kafka/publisher/usecase.py
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
@override
async def publish(
    self,
    *messages: "KafkaSendableMessage",
    topic: str = "",
    key: bytes | Any | None = None,
    partition: int | None = None,
    timestamp_ms: int | None = None,
    headers: dict[str, str] | None = None,
    reply_to: str = "",
    correlation_id: str | None = None,
    no_confirm: bool = False,
) -> Union["asyncio.Future[RecordMetadata]", "RecordMetadata"]:
    """Publish a message batch as a single request to broker.

    Args:
        *messages:
            Messages bodies to send.
        topic:
            Topic where the message will be published.
        key:
            A single key to associate with every message in this batch. If a
            partition is not specified and the producer uses the default
            partitioner, messages with the same key will be routed to the
            same partition. Must be bytes or serializable to bytes via the
            configured key serializer. If omitted, falls back to the
            publisher's default key (if configured).
        partition:
            Specify a partition. If not set, the partition will be
            selected using the configured `partitioner`
        timestamp_ms:
            Epoch milliseconds (from Jan 1 1970 UTC) to use as
            the message timestamp. Defaults to current time.
        headers:
            Message headers to store metainformation.
        reply_to:
            Reply message topic name to send response.
        correlation_id:
            Manual message **correlation_id** setter.
            **correlation_id** is a useful option to trace messages.
        no_confirm:
            Do not wait for Kafka publish confirmation.

    Returns:
        `asyncio.Future[RecordMetadata]` if no_confirm = True.
        `RecordMetadata` if no_confirm = False.
    """
    cmd = KafkaPublishCommand(
        *messages,
        key=key or self.key,
        topic=topic or self.topic,
        partition=partition if partition is not None else self.partition,
        reply_to=reply_to or self.reply_to,
        headers=self.headers | (headers or {}),
        correlation_id=correlation_id or self._outer_config.id_generator(),
        timestamp_ms=timestamp_ms,
        no_confirm=no_confirm,
        _publish_type=PublishType.PUBLISH,
    )

    return await self._basic_publish_batch(
        cmd,
        producer=self._outer_config.producer,
        _extra_middlewares=(),
    )