onestep 0.4.1__py3-none-any.whl → 0.4.3__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.

Potentially problematic release.


This version of onestep might be problematic. Click here for more details.

onestep/__init__.py CHANGED
@@ -11,6 +11,7 @@ from .middleware import (
11
11
  BaseMiddleware, BaseConfigMiddleware,
12
12
  NacosPublishConfigMiddleware, NacosConsumeConfigMiddleware,
13
13
  RedisPublishConfigMiddleware, RedisConsumeConfigMiddleware,
14
+ UniqueMiddleware, MemoryUniqueMiddleware,
14
15
  )
15
16
  from .exception import (
16
17
  StopMiddleware, DropMessage,
@@ -48,6 +49,8 @@ __all__ = [
48
49
  'NacosConsumeConfigMiddleware',
49
50
  'RedisPublishConfigMiddleware',
50
51
  'RedisConsumeConfigMiddleware',
52
+ 'UniqueMiddleware',
53
+ 'MemoryUniqueMiddleware',
51
54
 
52
55
  # exception
53
56
  'StopMiddleware',
@@ -59,4 +62,4 @@ __all__ = [
59
62
  '__version__'
60
63
  ]
61
64
 
62
- __version__ = '0.4.0'
65
+ __version__ = '0.4.3'
onestep/broker/base.py CHANGED
@@ -43,15 +43,15 @@ class BaseBroker:
43
43
  def add_middleware(self, middleware: BaseMiddleware):
44
44
  self.middlewares.append(middleware)
45
45
 
46
- def send(self, message):
46
+ def send(self, message, *args, **kwargs):
47
47
  """对消息进行预处理,然后再发送"""
48
48
  if not isinstance(message, Message):
49
49
  message = self.message_cls(body=message)
50
50
  # TODO: 对消息发送进行N次重试,确保消息发送成功。
51
- return self.publish(message.to_json())
51
+ return self.publish(message.to_json(), *args, **kwargs)
52
52
 
53
53
  @abc.abstractmethod
54
- def publish(self, message: Any):
54
+ def publish(self, message: Any, *args, **kwargs):
55
55
  """
56
56
  将消息原样发布到 broker 中。如果当前Broker是Job的to_broker, 则必须实现此方法
57
57
  """
onestep/broker/cron.py CHANGED
@@ -14,14 +14,15 @@ logger = logging.getLogger(__name__)
14
14
 
15
15
 
16
16
  class CronBroker(MemoryBroker):
17
- _thread = None
18
17
 
19
- def __init__(self, cron, name=None, middlewares=None, body: Any = None, *args, **kwargs):
18
+ def __init__(self, cron, name=None, middlewares=None, body: Any = None, start_time=None, *args, **kwargs):
20
19
  super().__init__(name=name, middlewares=middlewares, *args, **kwargs)
21
20
  self.cron = cron
22
- self.itr = croniter(cron, datetime.now())
21
+ self.start_time = start_time or datetime.now()
22
+ self.itr = croniter(cron, self.start_time)
23
23
  self.next_fire_time = self.itr.get_next(datetime)
24
24
  self.body = body
25
+ self._thread = None
25
26
 
26
27
  def _scheduler(self):
27
28
  if self.next_fire_time <= datetime.now():
@@ -36,7 +37,8 @@ class CronBroker(MemoryBroker):
36
37
  return CronConsumer(self, *args, **kwargs)
37
38
 
38
39
  def shutdown(self):
39
- self._thread.cancel()
40
+ if self._thread:
41
+ self._thread.cancel()
40
42
 
41
43
 
42
44
  class CronConsumer(MemoryConsumer):
onestep/broker/memory.py CHANGED
@@ -36,7 +36,7 @@ class MemoryBroker(BaseBroker):
36
36
  super().__init__(*args, **kwargs)
37
37
  self.queue = Queue(maxsize)
38
38
 
39
- def publish(self, message: Any):
39
+ def publish(self, message: Any, *args, **kwargs):
40
40
  try:
41
41
  self.queue.put_nowait(message)
42
42
  except FullException:
@@ -3,17 +3,21 @@ import threading
3
3
  from queue import Queue
4
4
  from typing import Optional, Dict, Any
5
5
 
6
- import amqpstorm
6
+ try:
7
+ import amqpstorm
8
+ from use_rabbitmq import useRabbitMQ as RabbitMQStore
9
+ except ImportError:
10
+ amqpstorm = None
11
+ RabbitMQStore = None
7
12
 
8
13
  from .base import BaseBroker, BaseConsumer
9
- from use_rabbitmq import useRabbitMQ as RabbitMQStore
10
14
  from ..message import Message
11
15
 
12
16
 
13
17
  class _RabbitMQMessage(Message):
14
18
 
15
19
  @classmethod
16
- def from_broker(cls, broker_message: amqpstorm.Message):
20
+ def from_broker(cls, broker_message):
17
21
  try:
18
22
  message = json.loads(broker_message.body)
19
23
  except json.JSONDecodeError:
@@ -30,20 +34,51 @@ class _RabbitMQMessage(Message):
30
34
  class RabbitMQBroker(BaseBroker):
31
35
  message_cls = _RabbitMQMessage
32
36
 
33
- def __init__(self, queue_name, params: Optional[Dict] = None, prefetch: Optional[int] = 1, auto_create=True, *args,
34
- **kwargs):
37
+ def __init__(
38
+ self,
39
+ queue_name,
40
+ params: Optional[Dict] = None,
41
+ prefetch: Optional[int] = 1,
42
+ auto_create: Optional[bool]=True,
43
+ queue_params: Optional[Dict]=None,
44
+ *args,
45
+ **kwargs
46
+ ):
47
+ """
48
+ Initializes the RabbitMQ broker.
49
+
50
+ Args:
51
+ queue_name (str): The name of the queue.
52
+ params (Optional[Dict], optional): Parameters for RabbitMQStore. Defaults to None.
53
+ prefetch (Optional[int], optional): Number of messages to prefetch. Defaults to 1.
54
+ auto_create (Optional[bool], optional): Whether to automatically create the queue. Defaults to True.
55
+ queue_params (Optional[Dict], optional): Parameters for queue declaration. Defaults to None.
56
+ *args: Variable length argument list.
57
+ **kwargs: Arbitrary keyword arguments.
58
+
59
+ Attributes:
60
+ queue_name (str): The name of the queue.
61
+ queue (Queue): The queue instance.
62
+ client (RabbitMQStore): The RabbitMQ client instance.
63
+ prefetch (int): Number of messages to prefetch.
64
+ threads (list): List of threads.
65
+ """
66
+
67
+ if RabbitMQStore is None:
68
+ raise ImportError("RabbitMQ dependencies not installed. Please install 'use-rabbitmq' package.")
69
+
35
70
  super().__init__(*args, **kwargs)
36
71
  self.queue_name = queue_name
37
72
  self.queue = Queue()
38
73
  params = params or {}
39
74
  self.client = RabbitMQStore(**params)
40
75
  if auto_create:
41
- self.client.declare_queue(self.queue_name)
76
+ self.client.declare_queue(self.queue_name, **(queue_params or {}))
42
77
  self.prefetch = prefetch
43
78
  self.threads = []
44
79
 
45
80
  def _consume(self, *args, **kwargs):
46
- def callback(message: amqpstorm.Message):
81
+ def callback(message):
47
82
  self.queue.put(message)
48
83
 
49
84
  prefetch = kwargs.pop("prefetch", self.prefetch)
@@ -57,8 +92,9 @@ class RabbitMQBroker(BaseBroker):
57
92
  self.threads.append(thread)
58
93
  return RabbitMQConsumer(self)
59
94
 
60
- def publish(self, message: Any):
61
- self.client.send(self.queue_name, message)
95
+ def publish(self, message: Any, properties: Optional[dict] = None, **kwargs):
96
+ """发布消息"""
97
+ self.client.send(self.queue_name, message, properties=properties, **kwargs)
62
98
 
63
99
  def confirm(self, message: Message):
64
100
  """确认消息"""
@@ -59,12 +59,12 @@ class RedisPubSubBroker(BaseBroker):
59
59
  self.threads.append(thread)
60
60
  return RedisPubSubConsumer(self)
61
61
 
62
- def send(self, message: Any):
62
+ def send(self, message: Any, *args, **kwargs):
63
63
  """Publish message to the Redis channel"""
64
64
  if not isinstance(message, Message):
65
65
  message = self.message_cls(body=message)
66
66
 
67
- self.client.publish(self.channel, message.to_json())
67
+ self.client.publish(self.channel, message.to_json(), *args, **kwargs)
68
68
 
69
69
  publish = send
70
70
 
@@ -75,12 +75,12 @@ class RedisStreamBroker(BaseBroker):
75
75
  self.threads.append(thread)
76
76
  return RedisStreamConsumer(self)
77
77
 
78
- def send(self, message: Any):
78
+ def send(self, message: Any, *args, **kwargs):
79
79
  """对消息进行预处理,然后再发送"""
80
80
  if not isinstance(message, Message):
81
81
  message = self.message_cls(body=message)
82
82
 
83
- self.client.send({"_message": message.to_json()})
83
+ self.client.send({"_message": message.to_json()}, *args, **kwargs)
84
84
 
85
85
  publish = send
86
86
 
onestep/broker/webhook.py CHANGED
@@ -57,13 +57,15 @@ class WebHookBroker(MemoryBroker):
57
57
  WebHookServer
58
58
  )
59
59
  self._servers[(self.host, self.port)] = hs
60
+ # 只有在创建新服务器时才启动线程
61
+ thread = threading.Thread(target=hs.serve_forever)
62
+ thread.daemon = True
63
+ thread.start()
64
+ self.threads.append(thread)
60
65
  else:
61
66
  hs = self._servers[(self.host, self.port)]
62
67
 
63
68
  WebHookServer.servers[(self.host, self.port)].append(Server(self.path, self.queue))
64
- thread = threading.Thread(target=hs.serve_forever)
65
- thread.start()
66
- self.threads.append(thread)
67
69
 
68
70
  def consume(self, *args, **kwargs):
69
71
  self._create_server()
@@ -71,7 +73,7 @@ class WebHookBroker(MemoryBroker):
71
73
  return WebHookConsumer(self, *args, **kwargs)
72
74
 
73
75
  def shutdown(self):
74
- hs = self._servers[(self.host, self.port)]
76
+ hs = self._servers.get((self.host, self.port))
75
77
  if hs:
76
78
  hs.shutdown()
77
79
  for thread in self.threads:
onestep/cli.py CHANGED
@@ -8,11 +8,17 @@ LOGFORMAT = "[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s"
8
8
 
9
9
 
10
10
  def setup_logging():
11
- logging.basicConfig(level=logging.DEBUG, format=LOGFORMAT, stream=sys.stdout)
11
+ # 设置全局日志级别为INFO,避免第三方库的DEBUG日志输出
12
+ logging.basicConfig(level=logging.INFO, format=LOGFORMAT, stream=sys.stdout)
12
13
 
13
14
  # exclude amqpstorm logs
14
15
  logging.getLogger("amqpstorm").setLevel(logging.CRITICAL)
15
- return logging.getLogger("onestep")
16
+
17
+ # 获取onestep的logger并设置为DEBUG级别以便调试
18
+ onestep_logger = logging.getLogger("onestep")
19
+ onestep_logger.setLevel(logging.DEBUG)
20
+
21
+ return onestep_logger
16
22
 
17
23
 
18
24
  logger = setup_logging()
@@ -1,7 +1,7 @@
1
1
  import hashlib
2
2
  import json
3
3
 
4
- from . import BaseMiddleware
4
+ from .base import BaseMiddleware
5
5
  from ..exception import DropMessage
6
6
 
7
7
 
onestep/onestep.py CHANGED
@@ -42,7 +42,7 @@ class BaseOneStep:
42
42
  self.workers = workers or DEFAULT_WORKERS
43
43
  self.worker_class = worker_class or DEFAULT_WORKER_CLASS
44
44
  if self.workers > MAX_WORKERS:
45
- logger.warning(f"workers[{self.workers}] litter than {MAX_WORKERS}")
45
+ logger.warning(f"workers[{self.workers}] greater than {MAX_WORKERS}")
46
46
  self.workers = MAX_WORKERS
47
47
  self.middlewares = middlewares or []
48
48
 
onestep/worker.py CHANGED
@@ -169,6 +169,8 @@ class ThreadWorker(BaseWorker):
169
169
 
170
170
 
171
171
  class ThreadPoolWorker(BaseWorker):
172
+ broker_exit: Dict[BaseBroker, bool] = {}
173
+ broker_exit_lock = threading.Lock()
172
174
 
173
175
  def __init__(self, onestep, broker: BaseBroker, workers=None, *args, **kwargs):
174
176
  super().__init__(onestep, broker, *args, **kwargs)
@@ -191,7 +193,8 @@ class ThreadPoolWorker(BaseWorker):
191
193
  self.shutdown()
192
194
  break
193
195
  for message in self.receive_messages():
194
- self.handle_message(message)
196
+ # 将消息处理提交到线程池中并发执行
197
+ self.executor.submit(self.handle_message, message)
195
198
 
196
199
  def shutdown(self):
197
200
  """关闭线程池 Worker"""
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: onestep
3
- Version: 0.4.1
3
+ Version: 0.4.3
4
4
  Summary: 仅需一步,轻松实现分布式异步任务。
5
5
  Author: miclon
6
6
  Author-email: jcnd@163.com
@@ -11,6 +11,8 @@ Classifier: Programming Language :: Python :: 3.9
11
11
  Classifier: Programming Language :: Python :: 3.10
12
12
  Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
14
16
  Provides-Extra: redis
15
17
  Requires-Dist: asgiref (>=3.6.0,<4.0.0)
16
18
  Requires-Dist: blinker (>=1.5,<2.0)
@@ -0,0 +1,27 @@
1
+ onestep/__init__.py,sha256=G-MOCgma1x23C6hAW6UIpsyCRFna-41SPyGX0CSaH3E,1517
2
+ onestep/_utils.py,sha256=ySYmy-o2o3BurvLfuLWKGXR8TLwug6aTDNMvA3_QjKM,414
3
+ onestep/broker/__init__.py,sha256=L-roNwPZVKsjytOlKCOlyAyvfejI28FyOj9uzfyXcrk,257
4
+ onestep/broker/base.py,sha256=G_MzKIbpDSPDx2rx-Q2rwourbcI_faBXQdQZRxjgx8s,4192
5
+ onestep/broker/cron.py,sha256=3CZGHftQKrNwzdKGtVG8uiPuDb3U5W1T6WI-fdY5ea4,1246
6
+ onestep/broker/memory.py,sha256=ycOWWHhWhiuNPMDqsbxKbMh8rpt84FlRsJkINLJNX1U,2070
7
+ onestep/broker/rabbitmq.py,sha256=c5rIkUprFlBIGZOdTI5_2tp6DmsdvD9u40Yp6-COQ-o,4301
8
+ onestep/broker/redis/__init__.py,sha256=lqjvBKpMGf6I34nyJTEAq7XU2a8aQemhMGCbb5aByFI,236
9
+ onestep/broker/redis/pubsub.py,sha256=m0QzBT--rftfTXSc6D3wTzfQrwUgv5mEEDnnER7nB9A,2708
10
+ onestep/broker/redis/stream.py,sha256=yUOD-Z0gzU5zNjRW1ZxNwl35i2pbJKTw33xIj0ga3vY,3504
11
+ onestep/broker/webhook.py,sha256=x8h6zGsgjGFQdzr-UVXW8vGGUM_XCllglSCBqXh4rtw,2501
12
+ onestep/cli.py,sha256=vXrMAg7Nl0Ra79DraBrCtQq8xJC443AUEqFXe7rVNYo,2133
13
+ onestep/exception.py,sha256=T-tqfRrJZT9Y85qe-1l-1PcHZzV2jxv-61HAhOc4AKE,753
14
+ onestep/message.py,sha256=W37HKnIDxpd5UmtDbPTw2DTb3lfxu9Vs2KYIiCr5b2s,4057
15
+ onestep/middleware/__init__.py,sha256=MP_45lqr4pecmbzQBnn2-AODQ0N_Fss8nl2SA7Zzljo,347
16
+ onestep/middleware/base.py,sha256=adWQ_Lx2Nkaw4ySojIaa3lwUIUu97pHR_l5YMr0lrbw,975
17
+ onestep/middleware/config.py,sha256=WZIvGXhpdSQRAFTbEWXcZdnhFcbvhGkLdkFIj-_QuZM,2438
18
+ onestep/middleware/unique.py,sha256=L4F4NnpDO6hReHa21tUiiPH5GRMeRNgGgC0o6zgu5v0,1355
19
+ onestep/onestep.py,sha256=PWAmjrrqXxnsh_CzA_pXET3Xe7jkKteWiIsfs5_gVaY,9373
20
+ onestep/retry.py,sha256=fPO139hQrcMjXZuQ4QfFaQR57VEqv_EKS2WSz92Ayvc,3706
21
+ onestep/signal.py,sha256=tz9bGzTFZeBviG_iaGLfy4OyFKlWat6szEI6kWEGfTA,337
22
+ onestep/state.py,sha256=UVG91CXCabU64X6qgcO0S7RzbBP8ut0ID7aTMww94us,618
23
+ onestep/worker.py,sha256=SLLaAjUA65i5PEHRbRzHaWLNokvrpPz1-BzSiZdbhqg,7029
24
+ onestep-0.4.3.dist-info/METADATA,sha256=fGTZznrO5qUZ-lD_3Gh_3hARAVLRxYW0k-KmcIZKshU,2675
25
+ onestep-0.4.3.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
26
+ onestep-0.4.3.dist-info/entry_points.txt,sha256=ZfWnNQqiGujz2PPLjSlKPocOFRryL7Ot0vQ41TU1xw0,44
27
+ onestep-0.4.3.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: poetry-core 2.2.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,27 +0,0 @@
1
- onestep/__init__.py,sha256=F38-j9JgPMyUe0zBf-ao-f2ailidPI_DJQE4ddGCOX0,1417
2
- onestep/_utils.py,sha256=ySYmy-o2o3BurvLfuLWKGXR8TLwug6aTDNMvA3_QjKM,414
3
- onestep/broker/__init__.py,sha256=L-roNwPZVKsjytOlKCOlyAyvfejI28FyOj9uzfyXcrk,257
4
- onestep/broker/base.py,sha256=Ryo-0YekdZfpfSSqdmh7jsmNONc_GmlYFYadt_n5bds,4141
5
- onestep/broker/cron.py,sha256=wKOm4k0IBPgZIq5gHC6ITVFUZwgCQ91AXzgL1eFT1WE,1135
6
- onestep/broker/memory.py,sha256=X7DDiEOiJE3WtocEC_NtSNfL8Jpo7BVQVSG_BJfNGNQ,2053
7
- onestep/broker/rabbitmq.py,sha256=LFlcpOV36D6bme5nUVsZ3WzJVFQazlKDKBcA9aQONRM,2928
8
- onestep/broker/redis/__init__.py,sha256=lqjvBKpMGf6I34nyJTEAq7XU2a8aQemhMGCbb5aByFI,236
9
- onestep/broker/redis/pubsub.py,sha256=_p2bKqXu0gYjKz2DsS8UdpkN5dCy94xf_xYx5NFuKpY,2674
10
- onestep/broker/redis/stream.py,sha256=uQJncD93Fz8pdP_NdgyQ1UAXwIouh7AFA9_naXaeiJM,3470
11
- onestep/broker/webhook.py,sha256=Zg22QxKPqJzdxjBsglUcL7P1RcM8FltcHpHXJiJPYgM,2392
12
- onestep/cli.py,sha256=JU3xQCy0Zc8Ou6AH4j37_bqw5GQ7C2wll9MWQZFo5jY,1902
13
- onestep/exception.py,sha256=T-tqfRrJZT9Y85qe-1l-1PcHZzV2jxv-61HAhOc4AKE,753
14
- onestep/message.py,sha256=W37HKnIDxpd5UmtDbPTw2DTb3lfxu9Vs2KYIiCr5b2s,4057
15
- onestep/middleware/__init__.py,sha256=MP_45lqr4pecmbzQBnn2-AODQ0N_Fss8nl2SA7Zzljo,347
16
- onestep/middleware/base.py,sha256=adWQ_Lx2Nkaw4ySojIaa3lwUIUu97pHR_l5YMr0lrbw,975
17
- onestep/middleware/config.py,sha256=WZIvGXhpdSQRAFTbEWXcZdnhFcbvhGkLdkFIj-_QuZM,2438
18
- onestep/middleware/unique.py,sha256=e3nWHW2yxHFWT9PqiA96sOA1CZZVTbC3bOwUgxN9iaQ,1351
19
- onestep/onestep.py,sha256=IQGOfhfbneXCaINqMzO-5wjWpmE5dISEZQtmG3bZ3EU,9372
20
- onestep/retry.py,sha256=fPO139hQrcMjXZuQ4QfFaQR57VEqv_EKS2WSz92Ayvc,3706
21
- onestep/signal.py,sha256=tz9bGzTFZeBviG_iaGLfy4OyFKlWat6szEI6kWEGfTA,337
22
- onestep/state.py,sha256=UVG91CXCabU64X6qgcO0S7RzbBP8ut0ID7aTMww94us,618
23
- onestep/worker.py,sha256=8Bmbie-KrZxnHbne1RvNL3v8j1PObfd12Yp9jmzAFYg,6855
24
- onestep-0.4.1.dist-info/METADATA,sha256=WoZmHjd1LmL9MvamCVyUsEakOTmReNSg2FSBHBCqd2w,2573
25
- onestep-0.4.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
26
- onestep-0.4.1.dist-info/entry_points.txt,sha256=ZfWnNQqiGujz2PPLjSlKPocOFRryL7Ot0vQ41TU1xw0,44
27
- onestep-0.4.1.dist-info/RECORD,,