async-task-kit 0.1.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.
@@ -0,0 +1,19 @@
1
+ from .consumer.coroutine import CoroutineConsumer
2
+ from .consumer.thread import ThreadConsumer
3
+ from .consumer.process import ProcessConsumer
4
+ from .consumer.base import BaseConsumer
5
+ from .core.processor import TaskProcessor
6
+ from .core.rabbitmq import RabbitMQ
7
+ from .utils.env_loader import EnvLoader
8
+ from .utils.logger import setup_logger
9
+
10
+ __all__ = [
11
+ "BaseConsumer",
12
+ "CoroutineConsumer",
13
+ "ThreadConsumer",
14
+ "ProcessConsumer",
15
+ "TaskProcessor",
16
+ "RabbitMQ",
17
+ "EnvLoader",
18
+ "setup_logger",
19
+ ]
@@ -0,0 +1,186 @@
1
+ Metadata-Version: 2.4
2
+ Name: async-task-kit
3
+ Version: 0.1.0
4
+ Summary: A powerful async task processing kit based on RabbitMQ with Coroutine, Thread, and Process support.
5
+ Author-email: realwrtoff <realwrtoff@gmail.com>
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.12
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: aio-pika>=9.4.0
13
+ Requires-Dist: python-dotenv>=1.0.0
14
+ Dynamic: license-file
15
+
16
+ # async-task-kit
17
+
18
+ A powerful async task processing kit based on RabbitMQ with Coroutine, Thread, and Process support.
19
+
20
+ ## Installation
21
+
22
+ ```bash
23
+ pip install async-task-kit
24
+ ```
25
+
26
+ ## Features
27
+
28
+ - **RabbitMQ Client**: Robust connection pooling and delay/dead-letter queue support.
29
+ - **Multiple Consumer Models**: Support for Coroutine (asyncio), Thread, and Process consumers depending on your workload (I/O-bound vs CPU-bound).
30
+ - **Extensible Processor**: Easily define your task logic by inheriting `TaskProcessor`.
31
+ - **Built-in Logger & EnvLoader**: Useful utilities for production-ready applications.
32
+
33
+ ## Quick Start
34
+
35
+ ### 1. Configuration (`.env`)
36
+
37
+ Use the built-in `EnvLoader` to manage your environment variables. Create a `.env` file:
38
+
39
+ ```env
40
+ RABBITMQ_URL=amqp://guest:guest@localhost/
41
+ TASK_IDS=demo_task
42
+
43
+ # You can also configure specific task settings using the {TASK_ID}_ prefix
44
+ DEMO_TASK_QUEUE_NAME=my_demo_queue
45
+ DEMO_TASK_CONCURRENCY=3
46
+ ```
47
+
48
+ ### 2. Define your Task Processor (`demo_processor.py`)
49
+
50
+ ```python
51
+ import logging
52
+ from async_task_kit import TaskProcessor
53
+
54
+ logger = logging.getLogger(__name__)
55
+
56
+ class DemoProcessor(TaskProcessor):
57
+ async def process(self, task: dict):
58
+ logger.info(f"Processing task: {task}")
59
+ # Return any truthy value (e.g., dict, object, True) for success and pass to callback.
60
+ # Return None or False to trigger retry.
61
+ return {"status": "ok", "processed_data": task}
62
+
63
+ async def callback(self, task: dict, result: any):
64
+ logger.info(f"Task completed with result: {result}")
65
+ ```
66
+
67
+ ### 3. Main Consumer Application (`main.py`)
68
+
69
+ A production-ready setup with signal handling for graceful shutdown.
70
+
71
+ ```python
72
+ import asyncio
73
+ import logging
74
+ import signal
75
+ from typing import List, Type
76
+
77
+ from demo_processor import DemoProcessor
78
+
79
+ # -------------- 只需要改这一行来切换并发模型 --------------
80
+ from async_task_kit import CoroutineConsumer as Consumer
81
+ # from async_task_kit import ThreadConsumer as Consumer
82
+ # from async_task_kit import ProcessConsumer as Consumer
83
+ # --------------------------------------------------------
84
+
85
+ from async_task_kit import TaskProcessor, EnvLoader, setup_logger
86
+
87
+ # Initialize logger
88
+ setup_logger()
89
+ logger = logging.getLogger(__name__)
90
+
91
+ # Register your processors
92
+ TASK_REGISTRY: dict[str, Type[TaskProcessor]] = {
93
+ "demo_task": DemoProcessor,
94
+ }
95
+
96
+ consumers: List[Consumer] = []
97
+
98
+ async def run_all_consumers(amqp_url: str, task_ids: List[str]):
99
+ tasks = []
100
+ for task_id in task_ids:
101
+ if task_id not in TASK_REGISTRY:
102
+ continue
103
+
104
+ processor_cls = TASK_REGISTRY[task_id]
105
+ processor = processor_cls(task_id=task_id)
106
+
107
+ consumer = Consumer(
108
+ amqp_url=amqp_url,
109
+ queue_name=processor.queue_name,
110
+ processor=processor,
111
+ concurrency=processor.concurrency,
112
+ )
113
+ consumers.append(consumer)
114
+ tasks.append(consumer.start())
115
+
116
+ logger.info(f"🚀 启动任务 [{task_id}] | queue={processor.queue_name} | 并发={processor.concurrency}")
117
+
118
+ await asyncio.gather(*tasks)
119
+
120
+ async def shutdown_all():
121
+ logger.info("🛑 优雅关闭所有消费者...")
122
+ for consumer in consumers:
123
+ await consumer.stop()
124
+ logger.info("✅ 所有消费者已关闭")
125
+
126
+ def handle_exit_signal(*args, **kwargs):
127
+ asyncio.create_task(shutdown_all())
128
+
129
+ async def main():
130
+ env = EnvLoader()
131
+ amqp_url = env.get("RABBITMQ_URL")
132
+ task_ids_str = env.get("TASK_IDS", "").strip()
133
+
134
+ if not task_ids_str:
135
+ logger.warning("⚠️ 未配置 TASK_IDS")
136
+ return
137
+
138
+ task_ids = [t.strip() for t in task_ids_str.split(",") if t.strip()]
139
+ valid_tasks = [t for t in task_ids if t in TASK_REGISTRY]
140
+
141
+ loop = asyncio.get_running_loop()
142
+ for sig in (signal.SIGINT, signal.SIGTERM):
143
+ loop.add_signal_handler(sig, handle_exit_signal)
144
+
145
+ await run_all_consumers(amqp_url, valid_tasks)
146
+
147
+ if __name__ == "__main__":
148
+ try:
149
+ asyncio.run(main())
150
+ except KeyboardInterrupt:
151
+ logger.info("👋 服务已安全退出")
152
+ ```
153
+
154
+ ### 4. Publishing Tasks (`publisher.py`)
155
+
156
+ ```python
157
+ import asyncio
158
+ import logging
159
+ from async_task_kit import RabbitMQ, setup_logger
160
+
161
+ setup_logger()
162
+ logger = logging.getLogger(__name__)
163
+
164
+ async def publish():
165
+ rmq = RabbitMQ("amqp://guest:guest@localhost/")
166
+ await rmq.init()
167
+
168
+ await rmq.push("my_demo_queue", {"message": "Hello from async-task-kit!"})
169
+ logger.info("Task published successfully.")
170
+
171
+ await rmq.close()
172
+
173
+ if __name__ == "__main__":
174
+ asyncio.run(publish())
175
+ ```
176
+
177
+ ## License
178
+
179
+ MIT
180
+
181
+ ## Contact & Support
182
+
183
+ If you have any questions, suggestions, or need help with this library, feel free to reach out!
184
+
185
+ **WeChat (微信)**: `realwrtoff`
186
+ **Email**: `realwrtoff@gmail.com`
@@ -0,0 +1,6 @@
1
+ async_task_kit/__init__.py,sha256=ZzNpjt8_OupDYLcPRrYjZpteBnzpaROGch5vEOCH71w,516
2
+ async_task_kit-0.1.0.dist-info/licenses/LICENSE,sha256=UtWDM6w7nMyyFqRyOZnsYCr408jfBPWGJGVXAx8pIKM,1065
3
+ async_task_kit-0.1.0.dist-info/METADATA,sha256=36Cs50fBLAG-0zNzTgd5EUo4rxrIKZD-WwJUmh4cPFM,5303
4
+ async_task_kit-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
5
+ async_task_kit-0.1.0.dist-info/top_level.txt,sha256=R1tW4mLUzZVPTc4z_d5VjWH7Q7sgGlOprYPslJo7jsI,15
6
+ async_task_kit-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Your Name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ async_task_kit