pulsar-lite 0.1.0__tar.gz

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.
@@ -0,0 +1,238 @@
1
+ Metadata-Version: 2.4
2
+ Name: pulsar-lite
3
+ Version: 0.1.0
4
+ Summary: Embedded Apache Pulsar-compatible broker for local development
5
+ Author-email: Ascentstream <community@ascentstream.com>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/ascentstream/pulsar-lite
8
+ Project-URL: Documentation, https://github.com/ascentstream/pulsar-lite#readme
9
+ Project-URL: Repository, https://github.com/ascentstream/pulsar-lite
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: pulsar-client>=3.0.0
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=7.0; extra == "dev"
24
+ Requires-Dist: black>=23.0; extra == "dev"
25
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
26
+
27
+ # Pulsar Lite
28
+
29
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/ascentstream/pulsar-lite/blob/main/LICENSE)
30
+
31
+ Pulsar Lite is a lightweight local broker that implements the core Apache Pulsar
32
+ binary protocol. This package ships a small Python helper that can start and
33
+ manage a local broker process, so you can use Pulsar topic names and the
34
+ official Pulsar Python client with a single local file path.
35
+
36
+ It is designed for fast local feedback, not as a production replacement for an
37
+ Apache Pulsar cluster. Use Apache Pulsar for production workloads that require
38
+ multi-broker scheduling, replication, capacity management, tenant isolation, or
39
+ operational SLAs.
40
+
41
+ ## Why use the Python helper
42
+
43
+ Many applications only need a local broker to validate the messaging path:
44
+ producers, consumers, subscriptions, flow control, failover, and key-based
45
+ routing. Setting up a full Pulsar deployment can be more expensive than the
46
+ test or prototype itself.
47
+
48
+ `pulsar-lite` keeps the client-facing API close to Pulsar while removing the
49
+ local setup cost:
50
+
51
+ - Start a local broker by passing a file path, no manual process management.
52
+ - Connect with the official `pulsar-client` (installed automatically).
53
+ - Use Pulsar topic names such as `persistent://...` and `non-persistent://...`.
54
+ - Exercise Shared, Failover, Exclusive, and KeyShared subscription behavior.
55
+
56
+ ## Installation
57
+
58
+ ```bash
59
+ pip install pulsar-lite
60
+ ```
61
+
62
+ The package declares `pulsar-client>=3.0.0` as a runtime dependency, so the
63
+ official Pulsar Python client is installed automatically.
64
+
65
+ Platform wheels include a prebuilt broker binary. If no wheel matches your
66
+ platform, see the [build from source](#building-the-broker-from-source) section.
67
+
68
+ ## Quick start: embedded mode
69
+
70
+ Pass a local file path and the helper starts a broker process for you:
71
+
72
+ ```python
73
+ import pulsar
74
+ from pulsar_lite import PulsarClient
75
+
76
+ topic = "non-persistent://public/default/quick-start"
77
+
78
+ with PulsarClient("./demo.db") as client:
79
+ consumer = client.subscribe(
80
+ topic,
81
+ "quick-start-sub",
82
+ consumer_type=pulsar.ConsumerType.Shared,
83
+ )
84
+ producer = client.create_producer(topic)
85
+
86
+ producer.send(b"hello from pulsar lite")
87
+ message = consumer.receive(timeout_millis=5000)
88
+ print(message.data().decode("utf-8"))
89
+ consumer.acknowledge(message)
90
+ ```
91
+
92
+ When the `PulsarClient` context exits, the embedded broker process is stopped
93
+ automatically (reference counted, so multiple clients on the same path share
94
+ one broker).
95
+
96
+ ## Quick start: remote mode
97
+
98
+ If you already have a broker running (locally or remotely), pass a `pulsar://`
99
+ URI instead and the helper acts as a thin wrapper over `pulsar.Client`:
100
+
101
+ ```python
102
+ import pulsar
103
+ from pulsar_lite import PulsarClient
104
+
105
+ with PulsarClient("pulsar://localhost:6650") as client:
106
+ producer = client.create_producer("non-persistent://public/default/events")
107
+ producer.send(b"event-1")
108
+ ```
109
+
110
+ You can also skip the helper entirely and use the official client directly,
111
+ since the broker speaks the standard Pulsar binary protocol:
112
+
113
+ ```python
114
+ import pulsar
115
+
116
+ client = pulsar.Client("pulsar://localhost:6650")
117
+ ```
118
+
119
+ ## Explicit broker lifecycle
120
+
121
+ For cases where you want to start the broker and then connect with the official
122
+ client (or multiple clients), use `start_broker`:
123
+
124
+ ```python
125
+ import pulsar
126
+ from pulsar_lite import start_broker
127
+
128
+ with start_broker("./demo.db") as broker:
129
+ client = pulsar.Client(broker.url)
130
+ # ... use the official client against broker.url ...
131
+ client.close()
132
+ ```
133
+
134
+ ## API
135
+
136
+ ### `PulsarClient(uri, **kwargs)`
137
+
138
+ - `uri`:
139
+ - A local file path (e.g. `"./demo.db"`) starts an embedded broker.
140
+ - A `pulsar://` or `pulsar+ssl://` URI connects to an existing broker.
141
+ - `**kwargs` are forwarded to `pulsar.Client`.
142
+ - Any attribute access not defined on `PulsarClient` itself is forwarded to the
143
+ underlying `pulsar.Client`, so the standard Pulsar API (`create_producer`,
144
+ `subscribe`, `get_topic_partitions`, ...) is fully available.
145
+ - Supports `with` statements and auto-closes the embedded broker on exit.
146
+
147
+ Properties:
148
+
149
+ | Property | Description |
150
+ | --- | --- |
151
+ | `is_embedded` | `True` when the helper started a local broker. |
152
+ | `db_path` | The absolute local file path (embedded mode only). |
153
+ | `pulsar_url` | The `pulsar://localhost:<port>` URL the client connects to. |
154
+
155
+ ### `start_broker(db_path) -> BrokerHandle`
156
+
157
+ Starts (or reuses) an embedded broker for the given path and returns a
158
+ `BrokerHandle` with `.url`, `.port`, and a `.stop()` method. Use it as a
159
+ context manager for automatic cleanup.
160
+
161
+ ## Topic names and subscription modes
162
+
163
+ Pulsar Lite accepts standard Pulsar topic URIs:
164
+
165
+ ```text
166
+ persistent://public/default/my-topic
167
+ non-persistent://public/default/my-topic
168
+ ```
169
+
170
+ Use `non-persistent://...` for live event dispatch where slow or disconnected
171
+ consumers should not create a durable backlog. Use `persistent://...` when a
172
+ test requires stored entries, cursor replay, or acknowledgements across restart
173
+ (requires a broker binary built with RocksDB storage support).
174
+
175
+ Supported subscription modes:
176
+
177
+ | Mode | Summary |
178
+ | --- | --- |
179
+ | Exclusive | One active consumer; additional consumers are rejected. |
180
+ | Failover | One active consumer with standby takeover. |
181
+ | Shared | Messages are distributed across available consumers. |
182
+ | KeyShared | Messages with the same key are routed to the same consumer. |
183
+
184
+ ## Binary discovery
185
+
186
+ The helper looks for the bundled broker binary in this order:
187
+
188
+ 1. The `pulsar_lite/bin/` directory shipped inside the wheel.
189
+ 2. The `PULSAR_LITE_BINARY` environment variable.
190
+ 3. The Rust release output at `rust/target/release/pulsar-lite` (development mode).
191
+ 4. The system `PATH`.
192
+ 5. Common install locations such as `/usr/local/bin/pulsar-lite`.
193
+
194
+ If you build the broker yourself, point `PULSAR_LITE_BINARY` at the resulting
195
+ binary instead of reinstalling the package.
196
+
197
+ ## Building the broker from source
198
+
199
+ If no prebuilt wheel matches your platform, build the broker from source and
200
+ let the helper discover it via `PULSAR_LITE_BINARY`:
201
+
202
+ ```bash
203
+ git clone https://github.com/ascentstream/pulsar-lite.git
204
+ cd pulsar-lite/rust
205
+ cargo build --release # core build
206
+ cargo build --release --features rocksdb-storage # with persistent storage
207
+ ```
208
+
209
+ Then install the Python package and point it at your binary:
210
+
211
+ ```bash
212
+ cd ../python
213
+ pip install -e .
214
+ export PULSAR_LITE_BINARY=$(pwd)/../rust/target/release/pulsar-lite
215
+ ```
216
+
217
+ ## Links
218
+
219
+ - Source: <https://github.com/ascentstream/pulsar-lite>
220
+ - Issues: <https://github.com/ascentstream/pulsar-lite/issues>
221
+ - Full documentation: <https://github.com/ascentstream/pulsar-lite#readme>
222
+
223
+ ## Project boundaries
224
+
225
+ Pulsar Lite intentionally does not provide:
226
+
227
+ - Multi-broker coordination or load balancing.
228
+ - Cross-cluster replication.
229
+ - Production-grade authorization or tenant governance.
230
+ - BookKeeper compatibility.
231
+ - Production durability or availability guarantees.
232
+
233
+ The project is useful for local development and compatibility testing, but
234
+ production deployments should use Apache Pulsar.
235
+
236
+ ## License
237
+
238
+ Pulsar Lite is licensed under the [Apache License 2.0](https://github.com/ascentstream/pulsar-lite/blob/main/LICENSE).
@@ -0,0 +1,212 @@
1
+ # Pulsar Lite
2
+
3
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/ascentstream/pulsar-lite/blob/main/LICENSE)
4
+
5
+ Pulsar Lite is a lightweight local broker that implements the core Apache Pulsar
6
+ binary protocol. This package ships a small Python helper that can start and
7
+ manage a local broker process, so you can use Pulsar topic names and the
8
+ official Pulsar Python client with a single local file path.
9
+
10
+ It is designed for fast local feedback, not as a production replacement for an
11
+ Apache Pulsar cluster. Use Apache Pulsar for production workloads that require
12
+ multi-broker scheduling, replication, capacity management, tenant isolation, or
13
+ operational SLAs.
14
+
15
+ ## Why use the Python helper
16
+
17
+ Many applications only need a local broker to validate the messaging path:
18
+ producers, consumers, subscriptions, flow control, failover, and key-based
19
+ routing. Setting up a full Pulsar deployment can be more expensive than the
20
+ test or prototype itself.
21
+
22
+ `pulsar-lite` keeps the client-facing API close to Pulsar while removing the
23
+ local setup cost:
24
+
25
+ - Start a local broker by passing a file path, no manual process management.
26
+ - Connect with the official `pulsar-client` (installed automatically).
27
+ - Use Pulsar topic names such as `persistent://...` and `non-persistent://...`.
28
+ - Exercise Shared, Failover, Exclusive, and KeyShared subscription behavior.
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ pip install pulsar-lite
34
+ ```
35
+
36
+ The package declares `pulsar-client>=3.0.0` as a runtime dependency, so the
37
+ official Pulsar Python client is installed automatically.
38
+
39
+ Platform wheels include a prebuilt broker binary. If no wheel matches your
40
+ platform, see the [build from source](#building-the-broker-from-source) section.
41
+
42
+ ## Quick start: embedded mode
43
+
44
+ Pass a local file path and the helper starts a broker process for you:
45
+
46
+ ```python
47
+ import pulsar
48
+ from pulsar_lite import PulsarClient
49
+
50
+ topic = "non-persistent://public/default/quick-start"
51
+
52
+ with PulsarClient("./demo.db") as client:
53
+ consumer = client.subscribe(
54
+ topic,
55
+ "quick-start-sub",
56
+ consumer_type=pulsar.ConsumerType.Shared,
57
+ )
58
+ producer = client.create_producer(topic)
59
+
60
+ producer.send(b"hello from pulsar lite")
61
+ message = consumer.receive(timeout_millis=5000)
62
+ print(message.data().decode("utf-8"))
63
+ consumer.acknowledge(message)
64
+ ```
65
+
66
+ When the `PulsarClient` context exits, the embedded broker process is stopped
67
+ automatically (reference counted, so multiple clients on the same path share
68
+ one broker).
69
+
70
+ ## Quick start: remote mode
71
+
72
+ If you already have a broker running (locally or remotely), pass a `pulsar://`
73
+ URI instead and the helper acts as a thin wrapper over `pulsar.Client`:
74
+
75
+ ```python
76
+ import pulsar
77
+ from pulsar_lite import PulsarClient
78
+
79
+ with PulsarClient("pulsar://localhost:6650") as client:
80
+ producer = client.create_producer("non-persistent://public/default/events")
81
+ producer.send(b"event-1")
82
+ ```
83
+
84
+ You can also skip the helper entirely and use the official client directly,
85
+ since the broker speaks the standard Pulsar binary protocol:
86
+
87
+ ```python
88
+ import pulsar
89
+
90
+ client = pulsar.Client("pulsar://localhost:6650")
91
+ ```
92
+
93
+ ## Explicit broker lifecycle
94
+
95
+ For cases where you want to start the broker and then connect with the official
96
+ client (or multiple clients), use `start_broker`:
97
+
98
+ ```python
99
+ import pulsar
100
+ from pulsar_lite import start_broker
101
+
102
+ with start_broker("./demo.db") as broker:
103
+ client = pulsar.Client(broker.url)
104
+ # ... use the official client against broker.url ...
105
+ client.close()
106
+ ```
107
+
108
+ ## API
109
+
110
+ ### `PulsarClient(uri, **kwargs)`
111
+
112
+ - `uri`:
113
+ - A local file path (e.g. `"./demo.db"`) starts an embedded broker.
114
+ - A `pulsar://` or `pulsar+ssl://` URI connects to an existing broker.
115
+ - `**kwargs` are forwarded to `pulsar.Client`.
116
+ - Any attribute access not defined on `PulsarClient` itself is forwarded to the
117
+ underlying `pulsar.Client`, so the standard Pulsar API (`create_producer`,
118
+ `subscribe`, `get_topic_partitions`, ...) is fully available.
119
+ - Supports `with` statements and auto-closes the embedded broker on exit.
120
+
121
+ Properties:
122
+
123
+ | Property | Description |
124
+ | --- | --- |
125
+ | `is_embedded` | `True` when the helper started a local broker. |
126
+ | `db_path` | The absolute local file path (embedded mode only). |
127
+ | `pulsar_url` | The `pulsar://localhost:<port>` URL the client connects to. |
128
+
129
+ ### `start_broker(db_path) -> BrokerHandle`
130
+
131
+ Starts (or reuses) an embedded broker for the given path and returns a
132
+ `BrokerHandle` with `.url`, `.port`, and a `.stop()` method. Use it as a
133
+ context manager for automatic cleanup.
134
+
135
+ ## Topic names and subscription modes
136
+
137
+ Pulsar Lite accepts standard Pulsar topic URIs:
138
+
139
+ ```text
140
+ persistent://public/default/my-topic
141
+ non-persistent://public/default/my-topic
142
+ ```
143
+
144
+ Use `non-persistent://...` for live event dispatch where slow or disconnected
145
+ consumers should not create a durable backlog. Use `persistent://...` when a
146
+ test requires stored entries, cursor replay, or acknowledgements across restart
147
+ (requires a broker binary built with RocksDB storage support).
148
+
149
+ Supported subscription modes:
150
+
151
+ | Mode | Summary |
152
+ | --- | --- |
153
+ | Exclusive | One active consumer; additional consumers are rejected. |
154
+ | Failover | One active consumer with standby takeover. |
155
+ | Shared | Messages are distributed across available consumers. |
156
+ | KeyShared | Messages with the same key are routed to the same consumer. |
157
+
158
+ ## Binary discovery
159
+
160
+ The helper looks for the bundled broker binary in this order:
161
+
162
+ 1. The `pulsar_lite/bin/` directory shipped inside the wheel.
163
+ 2. The `PULSAR_LITE_BINARY` environment variable.
164
+ 3. The Rust release output at `rust/target/release/pulsar-lite` (development mode).
165
+ 4. The system `PATH`.
166
+ 5. Common install locations such as `/usr/local/bin/pulsar-lite`.
167
+
168
+ If you build the broker yourself, point `PULSAR_LITE_BINARY` at the resulting
169
+ binary instead of reinstalling the package.
170
+
171
+ ## Building the broker from source
172
+
173
+ If no prebuilt wheel matches your platform, build the broker from source and
174
+ let the helper discover it via `PULSAR_LITE_BINARY`:
175
+
176
+ ```bash
177
+ git clone https://github.com/ascentstream/pulsar-lite.git
178
+ cd pulsar-lite/rust
179
+ cargo build --release # core build
180
+ cargo build --release --features rocksdb-storage # with persistent storage
181
+ ```
182
+
183
+ Then install the Python package and point it at your binary:
184
+
185
+ ```bash
186
+ cd ../python
187
+ pip install -e .
188
+ export PULSAR_LITE_BINARY=$(pwd)/../rust/target/release/pulsar-lite
189
+ ```
190
+
191
+ ## Links
192
+
193
+ - Source: <https://github.com/ascentstream/pulsar-lite>
194
+ - Issues: <https://github.com/ascentstream/pulsar-lite/issues>
195
+ - Full documentation: <https://github.com/ascentstream/pulsar-lite#readme>
196
+
197
+ ## Project boundaries
198
+
199
+ Pulsar Lite intentionally does not provide:
200
+
201
+ - Multi-broker coordination or load balancing.
202
+ - Cross-cluster replication.
203
+ - Production-grade authorization or tenant governance.
204
+ - BookKeeper compatibility.
205
+ - Production durability or availability guarantees.
206
+
207
+ The project is useful for local development and compatibility testing, but
208
+ production deployments should use Apache Pulsar.
209
+
210
+ ## License
211
+
212
+ Pulsar Lite is licensed under the [Apache License 2.0](https://github.com/ascentstream/pulsar-lite/blob/main/LICENSE).
@@ -0,0 +1,53 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pulsar-lite"
7
+ version = "0.1.0"
8
+ description = "Embedded Apache Pulsar-compatible broker for local development"
9
+ authors = [{name = "Ascentstream", email = "community@ascentstream.com"}]
10
+ license = {text = "Apache-2.0"}
11
+ readme = "README.md"
12
+ requires-python = ">=3.8"
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "Intended Audience :: Developers",
16
+ "License :: OSI Approved :: Apache Software License",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.8",
19
+ "Programming Language :: Python :: 3.9",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ ]
24
+ dependencies = [
25
+ "pulsar-client>=3.0.0",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ dev = [
30
+ "pytest>=7.0",
31
+ "black>=23.0",
32
+ "ruff>=0.1.0",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/ascentstream/pulsar-lite"
37
+ Documentation = "https://github.com/ascentstream/pulsar-lite#readme"
38
+ Repository = "https://github.com/ascentstream/pulsar-lite"
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
42
+
43
+ [tool.setuptools.package-data]
44
+ pulsar_lite = ["bin/pulsar-lite", "bin/pulsar-lite.exe"]
45
+
46
+ [tool.black]
47
+ line-length = 100
48
+ target-version = ['py38', 'py39', 'py310', 'py311', 'py312']
49
+
50
+ [tool.ruff]
51
+ line-length = 100
52
+ target-version = "py38"
53
+ select = ["E", "F", "I", "N", "W"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env python3
2
+ """Pulsar Lite setup customizations."""
3
+
4
+ import platform
5
+ import sys
6
+ import sysconfig
7
+
8
+ from setuptools import setup
9
+
10
+ try:
11
+ from setuptools.command.bdist_wheel import bdist_wheel
12
+ except ImportError:
13
+ from wheel.bdist_wheel import bdist_wheel
14
+
15
+
16
+ class bdist_platform_wheel(bdist_wheel):
17
+ """Build py3-none-platform wheels for the bundled Rust broker binary."""
18
+
19
+ def finalize_options(self):
20
+ super().finalize_options()
21
+ self.root_is_pure = False
22
+
23
+ def get_tag(self):
24
+ if self.plat_name_supplied:
25
+ plat_name = self.plat_name
26
+ elif self.plat_name and not self.plat_name.startswith("macosx"):
27
+ plat_name = self.plat_name
28
+ else:
29
+ plat_name = sysconfig.get_platform()
30
+ plat_name = _native_macos_platform(plat_name)
31
+
32
+ # Normalize to PEP 425 form (lowercase, underscores, no dots).
33
+ plat_name = plat_name.lower().replace("-", "_").replace(".", "_")
34
+
35
+ # PyPI rejects bare "linux_*" platform tags (PEP 513/599/600). The
36
+ # bundled Rust broker is a static binary with no glibc/ELIB coupling,
37
+ # so we relabel Linux wheels to manylinux_2_17 which is accepted by
38
+ # PyPI and works on any glibc >= 2.17 (CentOS 7+) distribution.
39
+ if plat_name == "linux_x86_64":
40
+ plat_name = "manylinux_2_17_x86_64"
41
+ elif plat_name == "linux_i686":
42
+ plat_name = "manylinux_2_17_i686"
43
+ elif plat_name == "linux_aarch64":
44
+ plat_name = "manylinux_2_17_aarch64"
45
+
46
+ # 32-bit x86 fallback for legacy i686 detection.
47
+ if plat_name in ("linux-x86_64", "linux_x86_64") and sys.maxsize == 2147483647:
48
+ plat_name = "manylinux_2_17_i686"
49
+
50
+ return self.python_tag, "none", plat_name
51
+
52
+
53
+ def _native_macos_platform(plat_name):
54
+ if not plat_name.startswith("macosx") or "universal2" not in plat_name:
55
+ return plat_name
56
+
57
+ machine = platform.machine().lower()
58
+ if machine in ("arm64", "aarch64"):
59
+ return "macosx-11.0-arm64"
60
+ if machine in ("x86_64", "amd64"):
61
+ return "macosx-10.9-x86_64"
62
+ return plat_name
63
+
64
+
65
+ if __name__ == "__main__":
66
+ setup(cmdclass={"bdist_wheel": bdist_platform_wheel})
@@ -0,0 +1,31 @@
1
+ """
2
+ Pulsar Lite - 嵌入式轻量级消息队列
3
+
4
+ 使用方式类似 Milvus Lite:
5
+ from pulsar_lite import PulsarClient
6
+
7
+ # 嵌入式模式 - 使用本地文件自动启动
8
+ client = PulsarClient("./milvus_demo.db")
9
+
10
+ # 远程模式 - 连接到远程服务器
11
+ client = PulsarClient("pulsar://localhost:6650")
12
+
13
+ # 使用标准 Pulsar API
14
+ producer = client.create_producer("my-topic")
15
+ producer.send(b"Hello World!")
16
+ client.close()
17
+
18
+ # 显式启动 broker,然后使用官方 pulsar-client
19
+ from pulsar_lite import start_broker
20
+ import pulsar
21
+
22
+ broker = start_broker("./milvus_demo.db")
23
+ client = pulsar.Client(broker.url)
24
+ """
25
+
26
+ __version__ = "0.1.0"
27
+
28
+ from .client import PulsarClient
29
+ from .process_manager import BrokerHandle, start_broker
30
+
31
+ __all__ = ["BrokerHandle", "PulsarClient", "start_broker", "__version__"]
@@ -0,0 +1,69 @@
1
+ """
2
+ 查找 Pulsar Lite 二进制文件
3
+ """
4
+
5
+ import os
6
+ import sys
7
+ import shutil
8
+ from pathlib import Path
9
+ from typing import Optional
10
+
11
+
12
+ def find_pulsar_lite_binary() -> str:
13
+ """
14
+ 查找 pulsar-lite 可执行文件
15
+
16
+ 搜索顺序:
17
+ 1. Python 包内置二进制(pip wheel 安装模式)
18
+ 2. 环境变量 PULSAR_LITE_BINARY
19
+ 3. 当前 Python 包目录的相对路径(开发模式)
20
+ 4. 系统 PATH
21
+ 5. 常见安装位置
22
+
23
+ Returns:
24
+ 二进制文件的绝对路径
25
+
26
+ Raises:
27
+ FileNotFoundError: 找不到二进制文件
28
+ """
29
+ # 1. 检查 Python 包内置二进制
30
+ package_binary_name = "pulsar-lite.exe" if sys.platform.startswith("win") else "pulsar-lite"
31
+ packaged_binary = Path(__file__).parent / "bin" / package_binary_name
32
+ if packaged_binary.is_file():
33
+ return str(packaged_binary.absolute())
34
+
35
+ # 2. 检查环境变量
36
+ env_path = os.environ.get("PULSAR_LITE_BINARY")
37
+ if env_path and os.path.isfile(env_path):
38
+ return os.path.abspath(env_path)
39
+
40
+ # 3. 开发模式:相对于当前包的路径
41
+ package_dir = Path(__file__).parent.parent.parent.parent # python/src/pulsar_lite -> 项目根目录
42
+ dev_binary = package_dir / "rust" / "target" / "release" / "pulsar-lite"
43
+ if dev_binary.exists():
44
+ return str(dev_binary.absolute())
45
+
46
+ # 4. 在 PATH 中查找
47
+ binary_name = package_binary_name
48
+ in_path = shutil.which(binary_name)
49
+ if in_path:
50
+ return in_path
51
+
52
+ # 5. 常见安装位置
53
+ common_paths = [
54
+ "/usr/local/bin/pulsar-lite",
55
+ "/usr/bin/pulsar-lite",
56
+ Path.home() / ".local" / "bin" / "pulsar-lite",
57
+ ]
58
+
59
+ for path in common_paths:
60
+ path = Path(path)
61
+ if path.exists():
62
+ return str(path.absolute())
63
+
64
+ raise FileNotFoundError(
65
+ "Pulsar Lite binary not found. Please either:\n"
66
+ "1. Set PULSAR_LITE_BINARY environment variable\n"
67
+ "2. Build from source: cd rust && cargo build --release\n"
68
+ "3. Install pulsar-lite to your PATH"
69
+ )
@@ -0,0 +1,116 @@
1
+ """
2
+ Pulsar Lite 客户端
3
+
4
+ 提供与 Milvus Lite 类似的无缝体验:
5
+ - 本地文件路径 → 自动启动嵌入式服务器
6
+ - 远程 URI → 直接连接远程服务器
7
+ """
8
+
9
+ import pulsar
10
+ from pathlib import Path
11
+ from typing import Optional, Any
12
+ from .process_manager import process_manager
13
+
14
+
15
+ class PulsarClient:
16
+ """
17
+ Pulsar Lite 客户端(兼容 Pulsar Python SDK API)
18
+
19
+ 使用方式类似 Milvus Lite:
20
+ # 嵌入式模式 - 使用本地文件自动启动
21
+ client = PulsarClient("./demo.db")
22
+
23
+ # 远程模式 - 连接到远程服务器
24
+ client = PulsarClient("pulsar://localhost:6650")
25
+
26
+ # 后续使用完全兼容 pulsar.Client API
27
+ producer = client.create_producer("my-topic")
28
+ producer.send(b"Hello")
29
+ """
30
+
31
+ def __init__(self, uri: str, **kwargs):
32
+ """
33
+ 初始化客户端
34
+
35
+ Args:
36
+ uri: 连接地址,可以是:
37
+ - 本地文件路径(如 "./demo.db")→ 自动启动嵌入式服务器
38
+ - Pulsar URI(如 "pulsar://localhost:6650")→ 直接连接远程
39
+ **kwargs: 传递给 pulsar.Client 的其他参数
40
+ """
41
+ self._original_uri = uri
42
+ self._db_path: Optional[str] = None
43
+ self._is_embedded = False
44
+ self._client: Optional[pulsar.Client] = None
45
+
46
+ # 判断是本地文件还是远程 URI
47
+ is_remote = uri.startswith("pulsar://") or uri.startswith("pulsar+ssl://")
48
+
49
+ if is_remote:
50
+ # 远程模式:直接连接
51
+ self._pulsar_url = uri
52
+ else:
53
+ # 嵌入式模式:启动本地服务器
54
+ self._db_path = str(Path(uri).absolute())
55
+ self._pulsar_url, self._port = process_manager.start_server(self._db_path)
56
+ self._is_embedded = True
57
+
58
+ # 创建实际的 Pulsar 客户端
59
+ self._client = pulsar.Client(self._pulsar_url, **kwargs)
60
+
61
+ def __getattr__(self, name: str) -> Any:
62
+ """
63
+ 代理所有其他方法到 pulsar.Client
64
+
65
+ 这样用户可以使用所有标准的 Pulsar API,如:
66
+ - create_producer
67
+ - subscribe
68
+ - get_topic_partitions
69
+ - 等等...
70
+ """
71
+ if self._client is None:
72
+ raise RuntimeError("Client has been closed")
73
+
74
+ return getattr(self._client, name)
75
+
76
+ def close(self):
77
+ """关闭客户端并释放资源"""
78
+ if self._client is not None:
79
+ self._client.close()
80
+ self._client = None
81
+
82
+ # 如果是嵌入式模式,停止服务器
83
+ if self._is_embedded and self._db_path:
84
+ process_manager.stop_server(self._db_path)
85
+ self._is_embedded = False
86
+
87
+ def __enter__(self):
88
+ """支持 with 语句"""
89
+ return self
90
+
91
+ def __exit__(self, exc_type, exc_val, exc_tb):
92
+ """退出 with 语句时自动关闭"""
93
+ self.close()
94
+ return False
95
+
96
+ def __del__(self):
97
+ """析构时自动关闭"""
98
+ try:
99
+ self.close()
100
+ except:
101
+ pass
102
+
103
+ @property
104
+ def is_embedded(self) -> bool:
105
+ """是否为嵌入式模式"""
106
+ return self._is_embedded
107
+
108
+ @property
109
+ def db_path(self) -> Optional[str]:
110
+ """数据库文件路径(仅嵌入式模式有效)"""
111
+ return self._db_path
112
+
113
+ @property
114
+ def pulsar_url(self) -> str:
115
+ """Pulsar 连接 URL"""
116
+ return self._pulsar_url
@@ -0,0 +1,236 @@
1
+ """
2
+ Pulsar Lite 进程管理器
3
+
4
+ 参考 Milvus Lite 的实现,管理嵌入式服务器进程
5
+ 支持多个客户端共享同一服务器实例
6
+ """
7
+
8
+ import os
9
+ import subprocess
10
+ import time
11
+ import threading
12
+ import socket
13
+ from dataclasses import dataclass
14
+ from pathlib import Path
15
+ from typing import Dict, Tuple, Optional
16
+ from .binary_finder import find_pulsar_lite_binary
17
+
18
+
19
+ @dataclass
20
+ class BrokerHandle:
21
+ """Handle for an embedded Pulsar Lite broker process."""
22
+
23
+ db_path: str
24
+ url: str
25
+ port: int
26
+
27
+ def stop(self):
28
+ """Release this handle and stop the broker when no clients remain."""
29
+ process_manager.stop_server(self.db_path)
30
+
31
+ def __enter__(self):
32
+ return self
33
+
34
+ def __exit__(self, exc_type, exc_val, exc_tb):
35
+ self.stop()
36
+ return False
37
+
38
+
39
+ class ProcessManager:
40
+ """
41
+ 单例进程管理器
42
+
43
+ 职责:
44
+ 1. 启动/停止 Pulsar Lite 服务器进程
45
+ 2. 引用计数:支持多个客户端共享同一实例
46
+ 3. 自动端口分配
47
+ 4. 线程安全
48
+ """
49
+
50
+ _instance = None
51
+ _lock = threading.Lock()
52
+
53
+ def __new__(cls):
54
+ if cls._instance is None:
55
+ with cls._lock:
56
+ if cls._instance is None:
57
+ cls._instance = super().__new__(cls)
58
+ cls._instance._initialized = False
59
+ return cls._instance
60
+
61
+ def __init__(self):
62
+ if self._initialized:
63
+ return
64
+
65
+ self._initialized = True
66
+ self._processes: Dict[str, Tuple[subprocess.Popen, int, int]] = {} # db_path -> (process, ref_count, port)
67
+ self._process_lock = threading.Lock()
68
+ self._binary_path = None
69
+
70
+ def _find_free_port(self, start_port: int = 6650) -> int:
71
+ """查找可用端口"""
72
+ port = start_port
73
+ while port < 6700:
74
+ try:
75
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
76
+ s.bind(("127.0.0.1", port))
77
+ return port
78
+ except OSError:
79
+ port += 1
80
+ raise RuntimeError("No available port found")
81
+
82
+ def _wait_until_ready(self, process: subprocess.Popen, port: int, timeout: float = 10.0):
83
+ """Wait until the broker accepts TCP connections on the selected port."""
84
+ deadline = time.time() + timeout
85
+ last_error = None
86
+
87
+ while time.time() < deadline:
88
+ if process.poll() is not None:
89
+ raise RuntimeError("Pulsar Lite server exited before accepting connections")
90
+
91
+ try:
92
+ with socket.create_connection(("127.0.0.1", port), timeout=0.25):
93
+ return
94
+ except OSError as error:
95
+ last_error = error
96
+ time.sleep(0.1)
97
+
98
+ try:
99
+ process.terminate()
100
+ process.wait(timeout=5)
101
+ except Exception:
102
+ process.kill()
103
+ process.wait()
104
+ raise RuntimeError(f"Pulsar Lite server did not become ready on port {port}: {last_error}")
105
+
106
+ def _is_remote_uri(self, uri: str) -> bool:
107
+ """判断是否为远程 URI"""
108
+ return uri.startswith("pulsar://") or uri.startswith("pulsar+ssl://")
109
+
110
+ def start_server(self, db_path: str) -> Tuple[str, int]:
111
+ """
112
+ 启动嵌入式服务器
113
+
114
+ Args:
115
+ db_path: 数据库文件路径
116
+
117
+ Returns:
118
+ (pulsar_url, port) - Pulsar 连接 URL 和端口号
119
+
120
+ Raises:
121
+ RuntimeError: 启动失败
122
+ """
123
+ # 规范化路径
124
+ db_path = str(Path(db_path).absolute())
125
+
126
+ with self._process_lock:
127
+ # 如果已经运行,增加引用计数
128
+ if db_path in self._processes:
129
+ process, ref_count, port = self._processes[db_path]
130
+ self._processes[db_path] = (process, ref_count + 1, port)
131
+ print(f"Reusing Pulsar Lite server for {db_path}, ref_count={ref_count + 1}, port={port}")
132
+ return f"pulsar://localhost:{port}", port
133
+
134
+ # 查找二进制文件
135
+ if self._binary_path is None:
136
+ self._binary_path = find_pulsar_lite_binary()
137
+
138
+ # 查找可用端口
139
+ port = self._find_free_port()
140
+ addr = f"127.0.0.1:{port}"
141
+
142
+ # 确保数据库目录存在
143
+ db_dir = Path(db_path).parent
144
+ db_dir.mkdir(parents=True, exist_ok=True)
145
+
146
+ # 启动进程,日志输出到 /tmp/pulsar-lite.log
147
+ env = {**os.environ, "RUST_LOG": "info"}
148
+ log_file = open("/tmp/pulsar-lite.log", "a")
149
+ process = subprocess.Popen(
150
+ [
151
+ self._binary_path,
152
+ "--addr",
153
+ addr,
154
+ "--db-path",
155
+ db_path,
156
+ ],
157
+ env=env,
158
+ stdout=log_file,
159
+ stderr=log_file,
160
+ cwd=str(db_dir)
161
+ )
162
+
163
+ try:
164
+ self._wait_until_ready(process, port)
165
+ except RuntimeError as error:
166
+ raise RuntimeError(f"Pulsar Lite server failed to start for {db_path}: {error}") from error
167
+
168
+ # 保存进程信息
169
+ self._processes[db_path] = (process, 1, port)
170
+ print(f"Started Pulsar Lite server for {db_path}, ref_count=1, port={port}, pid={process.pid}")
171
+
172
+ return f"pulsar://localhost:{port}", port
173
+
174
+ def start_broker(self, db_path: str) -> BrokerHandle:
175
+ """Start or reuse an embedded broker and return an explicit lifecycle handle."""
176
+ url, port = self.start_server(db_path)
177
+ return BrokerHandle(db_path=str(Path(db_path).absolute()), url=url, port=port)
178
+
179
+ def stop_server(self, db_path: str):
180
+ """
181
+ 停止嵌入式服务器(减少引用计数,为0时真正停止)
182
+
183
+ Args:
184
+ db_path: 数据库文件路径
185
+ """
186
+ db_path = str(Path(db_path).absolute())
187
+
188
+ with self._process_lock:
189
+ if db_path not in self._processes:
190
+ return
191
+
192
+ process, ref_count, port = self._processes[db_path]
193
+ ref_count -= 1
194
+
195
+ if ref_count == 0:
196
+ # 引用计数为0,停止服务器
197
+ print(f"Stopping Pulsar Lite server for {db_path}, pid={process.pid}")
198
+ try:
199
+ process.terminate()
200
+ process.wait(timeout=5)
201
+ except:
202
+ process.kill()
203
+ process.wait()
204
+
205
+ del self._processes[db_path]
206
+ print(f"Stopped Pulsar Lite server for {db_path}")
207
+ else:
208
+ # 更新引用计数
209
+ self._processes[db_path] = (process, ref_count, port)
210
+ print(f"Decreased ref_count for {db_path}, ref_count={ref_count}")
211
+
212
+ def stop_all(self):
213
+ """停止所有服务器"""
214
+ with self._process_lock:
215
+ for db_path, (process, _, _) in list(self._processes.items()):
216
+ print(f"Stopping Pulsar Lite server for {db_path}, pid={process.pid}")
217
+ try:
218
+ process.terminate()
219
+ process.wait(timeout=5)
220
+ except:
221
+ process.kill()
222
+ process.wait()
223
+
224
+ self._processes.clear()
225
+
226
+ def __del__(self):
227
+ self.stop_all()
228
+
229
+
230
+ # 全局单例
231
+ process_manager = ProcessManager()
232
+
233
+
234
+ def start_broker(db_path: str) -> BrokerHandle:
235
+ """Start or reuse an embedded Pulsar Lite broker."""
236
+ return process_manager.start_broker(db_path)
@@ -0,0 +1,238 @@
1
+ Metadata-Version: 2.4
2
+ Name: pulsar-lite
3
+ Version: 0.1.0
4
+ Summary: Embedded Apache Pulsar-compatible broker for local development
5
+ Author-email: Ascentstream <community@ascentstream.com>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/ascentstream/pulsar-lite
8
+ Project-URL: Documentation, https://github.com/ascentstream/pulsar-lite#readme
9
+ Project-URL: Repository, https://github.com/ascentstream/pulsar-lite
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: Apache Software License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Requires-Python: >=3.8
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: pulsar-client>=3.0.0
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=7.0; extra == "dev"
24
+ Requires-Dist: black>=23.0; extra == "dev"
25
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
26
+
27
+ # Pulsar Lite
28
+
29
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/ascentstream/pulsar-lite/blob/main/LICENSE)
30
+
31
+ Pulsar Lite is a lightweight local broker that implements the core Apache Pulsar
32
+ binary protocol. This package ships a small Python helper that can start and
33
+ manage a local broker process, so you can use Pulsar topic names and the
34
+ official Pulsar Python client with a single local file path.
35
+
36
+ It is designed for fast local feedback, not as a production replacement for an
37
+ Apache Pulsar cluster. Use Apache Pulsar for production workloads that require
38
+ multi-broker scheduling, replication, capacity management, tenant isolation, or
39
+ operational SLAs.
40
+
41
+ ## Why use the Python helper
42
+
43
+ Many applications only need a local broker to validate the messaging path:
44
+ producers, consumers, subscriptions, flow control, failover, and key-based
45
+ routing. Setting up a full Pulsar deployment can be more expensive than the
46
+ test or prototype itself.
47
+
48
+ `pulsar-lite` keeps the client-facing API close to Pulsar while removing the
49
+ local setup cost:
50
+
51
+ - Start a local broker by passing a file path, no manual process management.
52
+ - Connect with the official `pulsar-client` (installed automatically).
53
+ - Use Pulsar topic names such as `persistent://...` and `non-persistent://...`.
54
+ - Exercise Shared, Failover, Exclusive, and KeyShared subscription behavior.
55
+
56
+ ## Installation
57
+
58
+ ```bash
59
+ pip install pulsar-lite
60
+ ```
61
+
62
+ The package declares `pulsar-client>=3.0.0` as a runtime dependency, so the
63
+ official Pulsar Python client is installed automatically.
64
+
65
+ Platform wheels include a prebuilt broker binary. If no wheel matches your
66
+ platform, see the [build from source](#building-the-broker-from-source) section.
67
+
68
+ ## Quick start: embedded mode
69
+
70
+ Pass a local file path and the helper starts a broker process for you:
71
+
72
+ ```python
73
+ import pulsar
74
+ from pulsar_lite import PulsarClient
75
+
76
+ topic = "non-persistent://public/default/quick-start"
77
+
78
+ with PulsarClient("./demo.db") as client:
79
+ consumer = client.subscribe(
80
+ topic,
81
+ "quick-start-sub",
82
+ consumer_type=pulsar.ConsumerType.Shared,
83
+ )
84
+ producer = client.create_producer(topic)
85
+
86
+ producer.send(b"hello from pulsar lite")
87
+ message = consumer.receive(timeout_millis=5000)
88
+ print(message.data().decode("utf-8"))
89
+ consumer.acknowledge(message)
90
+ ```
91
+
92
+ When the `PulsarClient` context exits, the embedded broker process is stopped
93
+ automatically (reference counted, so multiple clients on the same path share
94
+ one broker).
95
+
96
+ ## Quick start: remote mode
97
+
98
+ If you already have a broker running (locally or remotely), pass a `pulsar://`
99
+ URI instead and the helper acts as a thin wrapper over `pulsar.Client`:
100
+
101
+ ```python
102
+ import pulsar
103
+ from pulsar_lite import PulsarClient
104
+
105
+ with PulsarClient("pulsar://localhost:6650") as client:
106
+ producer = client.create_producer("non-persistent://public/default/events")
107
+ producer.send(b"event-1")
108
+ ```
109
+
110
+ You can also skip the helper entirely and use the official client directly,
111
+ since the broker speaks the standard Pulsar binary protocol:
112
+
113
+ ```python
114
+ import pulsar
115
+
116
+ client = pulsar.Client("pulsar://localhost:6650")
117
+ ```
118
+
119
+ ## Explicit broker lifecycle
120
+
121
+ For cases where you want to start the broker and then connect with the official
122
+ client (or multiple clients), use `start_broker`:
123
+
124
+ ```python
125
+ import pulsar
126
+ from pulsar_lite import start_broker
127
+
128
+ with start_broker("./demo.db") as broker:
129
+ client = pulsar.Client(broker.url)
130
+ # ... use the official client against broker.url ...
131
+ client.close()
132
+ ```
133
+
134
+ ## API
135
+
136
+ ### `PulsarClient(uri, **kwargs)`
137
+
138
+ - `uri`:
139
+ - A local file path (e.g. `"./demo.db"`) starts an embedded broker.
140
+ - A `pulsar://` or `pulsar+ssl://` URI connects to an existing broker.
141
+ - `**kwargs` are forwarded to `pulsar.Client`.
142
+ - Any attribute access not defined on `PulsarClient` itself is forwarded to the
143
+ underlying `pulsar.Client`, so the standard Pulsar API (`create_producer`,
144
+ `subscribe`, `get_topic_partitions`, ...) is fully available.
145
+ - Supports `with` statements and auto-closes the embedded broker on exit.
146
+
147
+ Properties:
148
+
149
+ | Property | Description |
150
+ | --- | --- |
151
+ | `is_embedded` | `True` when the helper started a local broker. |
152
+ | `db_path` | The absolute local file path (embedded mode only). |
153
+ | `pulsar_url` | The `pulsar://localhost:<port>` URL the client connects to. |
154
+
155
+ ### `start_broker(db_path) -> BrokerHandle`
156
+
157
+ Starts (or reuses) an embedded broker for the given path and returns a
158
+ `BrokerHandle` with `.url`, `.port`, and a `.stop()` method. Use it as a
159
+ context manager for automatic cleanup.
160
+
161
+ ## Topic names and subscription modes
162
+
163
+ Pulsar Lite accepts standard Pulsar topic URIs:
164
+
165
+ ```text
166
+ persistent://public/default/my-topic
167
+ non-persistent://public/default/my-topic
168
+ ```
169
+
170
+ Use `non-persistent://...` for live event dispatch where slow or disconnected
171
+ consumers should not create a durable backlog. Use `persistent://...` when a
172
+ test requires stored entries, cursor replay, or acknowledgements across restart
173
+ (requires a broker binary built with RocksDB storage support).
174
+
175
+ Supported subscription modes:
176
+
177
+ | Mode | Summary |
178
+ | --- | --- |
179
+ | Exclusive | One active consumer; additional consumers are rejected. |
180
+ | Failover | One active consumer with standby takeover. |
181
+ | Shared | Messages are distributed across available consumers. |
182
+ | KeyShared | Messages with the same key are routed to the same consumer. |
183
+
184
+ ## Binary discovery
185
+
186
+ The helper looks for the bundled broker binary in this order:
187
+
188
+ 1. The `pulsar_lite/bin/` directory shipped inside the wheel.
189
+ 2. The `PULSAR_LITE_BINARY` environment variable.
190
+ 3. The Rust release output at `rust/target/release/pulsar-lite` (development mode).
191
+ 4. The system `PATH`.
192
+ 5. Common install locations such as `/usr/local/bin/pulsar-lite`.
193
+
194
+ If you build the broker yourself, point `PULSAR_LITE_BINARY` at the resulting
195
+ binary instead of reinstalling the package.
196
+
197
+ ## Building the broker from source
198
+
199
+ If no prebuilt wheel matches your platform, build the broker from source and
200
+ let the helper discover it via `PULSAR_LITE_BINARY`:
201
+
202
+ ```bash
203
+ git clone https://github.com/ascentstream/pulsar-lite.git
204
+ cd pulsar-lite/rust
205
+ cargo build --release # core build
206
+ cargo build --release --features rocksdb-storage # with persistent storage
207
+ ```
208
+
209
+ Then install the Python package and point it at your binary:
210
+
211
+ ```bash
212
+ cd ../python
213
+ pip install -e .
214
+ export PULSAR_LITE_BINARY=$(pwd)/../rust/target/release/pulsar-lite
215
+ ```
216
+
217
+ ## Links
218
+
219
+ - Source: <https://github.com/ascentstream/pulsar-lite>
220
+ - Issues: <https://github.com/ascentstream/pulsar-lite/issues>
221
+ - Full documentation: <https://github.com/ascentstream/pulsar-lite#readme>
222
+
223
+ ## Project boundaries
224
+
225
+ Pulsar Lite intentionally does not provide:
226
+
227
+ - Multi-broker coordination or load balancing.
228
+ - Cross-cluster replication.
229
+ - Production-grade authorization or tenant governance.
230
+ - BookKeeper compatibility.
231
+ - Production durability or availability guarantees.
232
+
233
+ The project is useful for local development and compatibility testing, but
234
+ production deployments should use Apache Pulsar.
235
+
236
+ ## License
237
+
238
+ Pulsar Lite is licensed under the [Apache License 2.0](https://github.com/ascentstream/pulsar-lite/blob/main/LICENSE).
@@ -0,0 +1,13 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.py
4
+ src/pulsar_lite/__init__.py
5
+ src/pulsar_lite/binary_finder.py
6
+ src/pulsar_lite/client.py
7
+ src/pulsar_lite/process_manager.py
8
+ src/pulsar_lite.egg-info/PKG-INFO
9
+ src/pulsar_lite.egg-info/SOURCES.txt
10
+ src/pulsar_lite.egg-info/dependency_links.txt
11
+ src/pulsar_lite.egg-info/requires.txt
12
+ src/pulsar_lite.egg-info/top_level.txt
13
+ src/pulsar_lite/bin/pulsar-lite
@@ -0,0 +1,6 @@
1
+ pulsar-client>=3.0.0
2
+
3
+ [dev]
4
+ pytest>=7.0
5
+ black>=23.0
6
+ ruff>=0.1.0
@@ -0,0 +1 @@
1
+ pulsar_lite