Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions core/sdk/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ pub use iggy_common::{
Aes256GcmEncryptor, Args, ArgsOptional, AutoLogin, CacheMetrics, CacheMetricsKey, ClientError,
ClientInfoDetails, ClusterMetadata, ClusterNode, ClusterNodeRole, ClusterNodeStatus,
CompressionAlgorithm, Consumer, ConsumerGroup, ConsumerGroupDetails, ConsumerGroupMember,
ConsumerKind, EncryptorKind, GlobalPermissions, HeaderKey, HeaderKind, HeaderValue,
HttpClientConfig, HttpClientConfigBuilder, HttpMethod, IdKind, Identifier, IdentityInfo,
IggyByteSize, IggyDuration, IggyError, IggyExpiry, IggyIndexView, IggyMessage,
ConsumerKind, Credentials, EncryptorKind, GlobalPermissions, HeaderKey, HeaderKind,
HeaderValue, HttpClientConfig, HttpClientConfigBuilder, HttpMethod, IdKind, Identifier,
IdentityInfo, IggyByteSize, IggyDuration, IggyError, IggyExpiry, IggyIndexView, IggyMessage,
IggyMessageHeader, IggyMessageHeaderView, IggyMessageView, IggyMessageViewIterator,
IggyTimestamp, MaxTopicSize, Partition, Partitioner, Partitioning, Permissions,
PersonalAccessTokenExpiry, PollMessages, PolledMessages, PollingKind, PollingStrategy,
Expand Down
14 changes: 14 additions & 0 deletions examples/python/README.md

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this extra change if the above example gets folded in getting-started.

Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,20 @@ python basic/consumer.py

Demonstrates fundamental client connection, authentication, batch message sending, and polling with support for TCP/QUIC/HTTP protocols.

### Client Configuration

Auto-login and reconnection, configured explicitly rather than through a connection string:

```bash
# Using uv
uv run client-configuration/main.py

# Without using uv
python client-configuration/main.py
```

Demonstrates `TcpConfig`, `TcpReconnectionConfig` and `AutoLogin`. Because the credentials are replayed on every connect, the client recovers its session after the server restarts instead of failing with `Unauthenticated`.

## TLS Examples

To test with a TLS-enabled server, start the server with TLS configured (see main README), then run:
Expand Down
142 changes: 142 additions & 0 deletions examples/python/client-configuration/main.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need for an extra example for the new config. Let's fold this into the getting-started/ example

Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

"""
Configures the TCP client explicitly instead of passing a bare address.

The point of `auto_login` is that the credentials are replayed every time the
client connects, including after a reconnect. That is what lets the SDK
recover a session the server dropped: without it, a restart of the server
surfaces as `Unauthenticated` on the next call and the application has to
reconnect and log in by hand.

Run this, then restart the server while it is polling: the client reconnects,
replays the login and keeps going.
"""

import argparse
import asyncio
import typing
from datetime import timedelta

from apache_iggy import (
AutoLogin,
IggyClient,
PollingStrategy,
StreamDetails,
TcpConfig,
TcpReconnectionConfig,
TopicDetails,
)
from apache_iggy import SendMessage as Message
from loguru import logger

STREAM_NAME = "configured-stream"
TOPIC_NAME = "configured-topic"
PARTITION_ID = 0
BATCHES_LIMIT = 5


class ArgNamespace(typing.NamedTuple):
tcp_server_address: str
username: str
password: str


def parse_args() -> ArgNamespace:
parser = argparse.ArgumentParser()
parser.add_argument(
"--tcp-server-address",
default="127.0.0.1:8090",
help="Iggy TCP server address (host:port)",
)
parser.add_argument("--username", default="iggy", help="Username to log in with")
parser.add_argument("--password", default="iggy", help="Password to log in with")
return ArgNamespace(**vars(parser.parse_args()))


def build_config(args: ArgNamespace) -> TcpConfig:
return TcpConfig(
server_address=args.tcp_server_address,
auto_login=AutoLogin.username_password(args.username, args.password),
reconnection=TcpReconnectionConfig(
enabled=True,
max_retries=None, # retry forever
interval=timedelta(seconds=1),
reestablish_after=timedelta(seconds=5),
),
heartbeat_interval=timedelta(seconds=5),
nodelay=True,
)


async def main():
args = parse_args()
config = build_config(args)
logger.info(f"Connecting with {config}")

client = IggyClient(config)
# No login_user() call: auto_login replays the credentials on every connect.
await client.connect()
logger.info("Connected and authenticated.")

await init_system(client)
await produce_and_consume(client)


async def init_system(client: IggyClient):
stream: StreamDetails | None = await client.get_stream(STREAM_NAME)
if stream is None:
await client.create_stream(name=STREAM_NAME)
logger.info(f"Created stream {STREAM_NAME}.")

topic: TopicDetails | None = await client.get_topic(STREAM_NAME, TOPIC_NAME)
if topic is None:
await client.create_topic(
stream=STREAM_NAME,
name=TOPIC_NAME,
partitions_count=1,
replication_factor=1,
)
logger.info(f"Created topic {TOPIC_NAME}.")


async def produce_and_consume(client: IggyClient):
for batch in range(BATCHES_LIMIT):
messages = [Message(f"message-{batch}-{i}") for i in range(10)]
await client.send_messages(
stream=STREAM_NAME,
topic=TOPIC_NAME,
partitioning=PARTITION_ID,
messages=messages,
)
logger.info(f"Sent batch {batch}.")

polled = await client.poll_messages(
stream=STREAM_NAME,
topic=TOPIC_NAME,
partition_id=PARTITION_ID,
polling_strategy=PollingStrategy.Next(),
count=len(messages),
auto_commit=True,
)
logger.info(f"Polled {len(polled)} messages.")
await asyncio.sleep(0.5)


if __name__ == "__main__":
asyncio.run(main())
1 change: 1 addition & 0 deletions foreign/python/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,5 @@ pyo3-async-runtimes = { version = "0.29.0", features = [
"tokio-runtime",
] }
pyo3-stub-gen = "0.23.0"
secrecy = "0.10"
tokio = "1.53.1"
38 changes: 38 additions & 0 deletions foreign/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,44 @@ maturin develop
pytest tests/ -v # Run tests (requires iggy-server running)
```

## Client Configuration

`IggyClient` takes either a server address or a `TcpConfig`. Configuring `auto_login`
lets the SDK replay the credentials whenever it reconnects, so a session dropped by a
server restart is recovered instead of surfacing as `Unauthenticated`:
Comment on lines +63 to +65

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to mention the auto_login option specially. That is for the API comment docs.


```python
import asyncio
from datetime import timedelta

from apache_iggy import AutoLogin, IggyClient, TcpConfig, TcpReconnectionConfig


async def main():
client = IggyClient(
TcpConfig(
server_address="127.0.0.1:8090",
auto_login=AutoLogin.username_password("iggy", "iggy"),
reconnection=TcpReconnectionConfig(
enabled=True,
max_retries=10,
interval=timedelta(seconds=2),
reestablish_after=timedelta(seconds=30),
),
heartbeat_interval=timedelta(seconds=5),
)
)
await client.connect()


asyncio.run(main())
```

`TcpConfig` also carries `tls_enabled`, `tls_domain`, `tls_ca_file`,
`tls_validate_certificate` and `nodelay`. Every field is keyword-only and defaults to the
same value the Rust SDK uses. `IggyClient.from_connection_string(...)` remains available
for the same settings in string form.
Comment on lines +94 to +97

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could show these as commented out options in the above config instead of mentioning them here. No need to mention anything about from_connection_string here.


## Examples

Refer to the [examples/python/](https://github.com/apache/iggy/tree/master/examples/python) directory for usage examples.
Expand Down
Loading
Loading