jararaca 0.3.12a11__py3-none-any.whl → 0.3.12a13__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 jararaca might be problematic. Click here for more details.

@@ -1,4 +1,5 @@
1
1
  import asyncio
2
+ import logging
2
3
  from dataclasses import dataclass
3
4
  from typing import Any
4
5
 
@@ -10,6 +11,8 @@ from jararaca.presentation.websocket.websocket_interceptor import (
10
11
  WebSocketConnectionBackend,
11
12
  )
12
13
 
14
+ logger = logging.getLogger(__name__)
15
+
13
16
 
14
17
  @dataclass
15
18
  class BroadcastMessage:
@@ -55,6 +58,7 @@ class RedisWebSocketConnectionBackend(WebSocketConnectionBackend):
55
58
  send_pubsub_channel: str,
56
59
  consume_broadcast_timeout: int = 1,
57
60
  consume_send_timeout: int = 1,
61
+ retry_delay: float = 5.0,
58
62
  ) -> None:
59
63
 
60
64
  self.redis = conn
@@ -66,6 +70,35 @@ class RedisWebSocketConnectionBackend(WebSocketConnectionBackend):
66
70
 
67
71
  self.consume_broadcast_timeout = consume_broadcast_timeout
68
72
  self.consume_send_timeout = consume_send_timeout
73
+ self.retry_delay = retry_delay
74
+ self.__shutdown_event: asyncio.Event | None = None
75
+
76
+ self.__send_func: SendFunc | None = None
77
+ self.__broadcast_func: BroadcastFunc | None = None
78
+
79
+ @property
80
+ def shutdown_event(self) -> asyncio.Event:
81
+ if self.__shutdown_event is None:
82
+ raise RuntimeError(
83
+ "Shutdown event is not set. Please configure the backend before using it."
84
+ )
85
+ return self.__shutdown_event
86
+
87
+ @property
88
+ def send_func(self) -> SendFunc:
89
+ if self.__send_func is None:
90
+ raise RuntimeError(
91
+ "Send function is not set. Please configure the backend before using it."
92
+ )
93
+ return self.__send_func
94
+
95
+ @property
96
+ def broadcast_func(self) -> BroadcastFunc:
97
+ if self.__broadcast_func is None:
98
+ raise RuntimeError(
99
+ "Broadcast function is not set. Please configure the backend before using it."
100
+ )
101
+ return self.__broadcast_func
69
102
 
70
103
  async def broadcast(self, message: bytes) -> None:
71
104
  await self.redis.publish(
@@ -82,22 +115,95 @@ class RedisWebSocketConnectionBackend(WebSocketConnectionBackend):
82
115
  def configure(
83
116
  self, broadcast: BroadcastFunc, send: SendFunc, shutdown_event: asyncio.Event
84
117
  ) -> None:
118
+ if self.__shutdown_event is not None:
119
+ raise RuntimeError("Backend is already configured.")
120
+ self.__shutdown_event = shutdown_event
121
+ self.__send_func = send
122
+ self.__broadcast_func = broadcast
123
+ self.setup_send_consumer()
124
+ self.setup_broadcast_consumer()
85
125
 
86
- broadcast_task = asyncio.get_event_loop().create_task(
87
- self.consume_broadcast(broadcast, shutdown_event)
88
- )
126
+ def setup_send_consumer(self) -> None:
89
127
 
90
128
  send_task = asyncio.get_event_loop().create_task(
91
- self.consume_send(send, shutdown_event)
129
+ self.consume_send(self.send_func, self.shutdown_event)
92
130
  )
93
131
 
94
- self.tasks.add(broadcast_task)
95
132
  self.tasks.add(send_task)
133
+ send_task.add_done_callback(self.handle_send_task_done)
134
+
135
+ def setup_broadcast_consumer(self) -> None:
136
+
137
+ broadcast_task = asyncio.get_event_loop().create_task(
138
+ self.consume_broadcast(self.broadcast_func, self.shutdown_event)
139
+ )
140
+
141
+ self.tasks.add(broadcast_task)
142
+
143
+ broadcast_task.add_done_callback(self.handle_broadcast_task_done)
144
+
145
+ def handle_broadcast_task_done(self, task: asyncio.Task[Any]) -> None:
146
+ if task.cancelled():
147
+ logger.warning("Broadcast task was cancelled.")
148
+ elif task.exception() is not None:
149
+ logger.exception(
150
+ f"Broadcast task raised an exception:", exc_info=task.exception()
151
+ )
152
+ else:
153
+ logger.warning("Broadcast task somehow completed successfully.")
154
+
155
+ if not self.shutdown_event.is_set():
156
+ logger.warning(
157
+ "Broadcast task completed, but shutdown event is not set. This is unexpected."
158
+ )
159
+ # Add delay before retrying to avoid excessive CPU usage
160
+ asyncio.get_event_loop().create_task(
161
+ self._retry_broadcast_consumer_with_delay()
162
+ )
163
+
164
+ def handle_send_task_done(self, task: asyncio.Task[Any]) -> None:
165
+ if task.cancelled():
166
+ logger.warning("Send task was cancelled.")
167
+ elif task.exception() is not None:
168
+ logger.exception(
169
+ f"Send task raised an exception:", exc_info=task.exception()
170
+ )
171
+ else:
172
+ logger.warning("Send task somehow completed successfully.")
173
+
174
+ if not self.shutdown_event.is_set():
175
+ logger.warning(
176
+ "Send task completed, but shutdown event is not set. This is unexpected."
177
+ )
178
+ # Add delay before retrying to avoid excessive CPU usage
179
+ asyncio.get_event_loop().create_task(self._retry_send_consumer_with_delay())
180
+
181
+ async def _retry_broadcast_consumer_with_delay(self) -> None:
182
+ """Retry setting up broadcast consumer after a delay to avoid excessive CPU usage."""
183
+ logger.info(
184
+ f"Waiting {self.retry_delay} seconds before retrying broadcast consumer..."
185
+ )
186
+ await asyncio.sleep(self.retry_delay)
187
+
188
+ if not self.shutdown_event.is_set():
189
+ logger.info("Retrying broadcast consumer setup...")
190
+ self.setup_broadcast_consumer()
191
+
192
+ async def _retry_send_consumer_with_delay(self) -> None:
193
+ """Retry setting up send consumer after a delay to avoid excessive CPU usage."""
194
+ logger.info(
195
+ f"Waiting {self.retry_delay} seconds before retrying send consumer..."
196
+ )
197
+ await asyncio.sleep(self.retry_delay)
198
+
199
+ if not self.shutdown_event.is_set():
200
+ logger.info("Retrying send consumer setup...")
201
+ self.setup_send_consumer()
96
202
 
97
203
  async def consume_broadcast(
98
204
  self, broadcast: BroadcastFunc, shutdown_event: asyncio.Event
99
205
  ) -> None:
100
-
206
+ logger.info("Starting broadcast consumer...")
101
207
  async with self.redis.pubsub() as pubsub:
102
208
  await pubsub.subscribe(self.broadcast_pubsub_channel)
103
209
 
@@ -122,7 +228,7 @@ class RedisWebSocketConnectionBackend(WebSocketConnectionBackend):
122
228
  task.add_done_callback(self.tasks.discard)
123
229
 
124
230
  async def consume_send(self, send: SendFunc, shutdown_event: asyncio.Event) -> None:
125
-
231
+ logger.info("Starting send consumer...")
126
232
  async with self.redis.pubsub() as pubsub:
127
233
  await pubsub.subscribe(self.send_pubsub_channel)
128
234
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jararaca
3
- Version: 0.3.12a11
3
+ Version: 0.3.12a13
4
4
  Summary: A simple and fast API framework for Python
5
5
  Home-page: https://github.com/LuscasLeo/jararaca
6
6
  Author: Lucas S
@@ -1,6 +1,6 @@
1
1
  LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
2
2
  README.md,sha256=2qMM__t_MoLKZr4IY9tXjo-Jn6LKjuHMb1qbyXpgL08,3401
3
- pyproject.toml,sha256=uOD1sjQvYMshstzAtrSkxvKtqKX_SheTuywTHkupokM,2041
3
+ pyproject.toml,sha256=2b0HUhZMnedp1Sb0K1oRqNFT3ABK4eeo0_Hr66AOaME,2041
4
4
  jararaca/__init__.py,sha256=h3MkFZ9xNllb-YTB-M1WH2HnSJbkev6t1c984Nn6G1w,21887
5
5
  jararaca/__main__.py,sha256=-O3vsB5lHdqNFjUtoELDF81IYFtR-DSiiFMzRaiSsv4,67
6
6
  jararaca/broker_backend/__init__.py,sha256=GzEIuHR1xzgCJD4FE3harNjoaYzxHMHoEL0_clUaC-k,3528
@@ -47,7 +47,7 @@ jararaca/presentation/websocket/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
47
47
  jararaca/presentation/websocket/base_types.py,sha256=AvUeeZ1TFhSiRMcYqZU1HaQNqSrcgTkC5R0ArP5dGmA,146
48
48
  jararaca/presentation/websocket/context.py,sha256=A6K5W3kqo9Hgeh1m6JiI7Cdz5SfbXcaICSVX7u1ARZo,1903
49
49
  jararaca/presentation/websocket/decorators.py,sha256=ZNd5aoA9UkyfHOt1C8D2Ffy2gQUNDEsusVnQuTgExgs,2157
50
- jararaca/presentation/websocket/redis.py,sha256=6wD4zGHftJXNDW3VfS65WJt2cnOgTI0zmQOfjZ_CEXE,4726
50
+ jararaca/presentation/websocket/redis.py,sha256=XG_kfr-msgEdfIZkD5JB_GH5lWoEHXwTzpQNVOONvfc,8985
51
51
  jararaca/presentation/websocket/types.py,sha256=M8snAMSdaQlKrwEM2qOgF2qrefo5Meio_oOw620Joc8,308
52
52
  jararaca/presentation/websocket/websocket_interceptor.py,sha256=JWn_G8Q2WO0-1kmN7-Gv0HkIM6nZ_yjCdGRuXUS8F7A,9191
53
53
  jararaca/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -74,8 +74,8 @@ jararaca/tools/typescript/interface_parser.py,sha256=SsTgYUWhX79e2rvcu5A5kvs7bJ3
74
74
  jararaca/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
75
  jararaca/utils/rabbitmq_utils.py,sha256=ytdAFUyv-OBkaVnxezuJaJoLrmN7giZgtKeet_IsMBs,10918
76
76
  jararaca/utils/retry.py,sha256=DzPX_fXUvTqej6BQ8Mt2dvLo9nNlTBm7Kx2pFZ26P2Q,4668
77
- jararaca-0.3.12a11.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
78
- jararaca-0.3.12a11.dist-info/METADATA,sha256=kgieepWNDIL1SoFMf_fTt3zKQuHZ0gYWjZDVFeG13ow,4996
79
- jararaca-0.3.12a11.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
80
- jararaca-0.3.12a11.dist-info/entry_points.txt,sha256=WIh3aIvz8LwUJZIDfs4EeH3VoFyCGEk7cWJurW38q0I,45
81
- jararaca-0.3.12a11.dist-info/RECORD,,
77
+ jararaca-0.3.12a13.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
78
+ jararaca-0.3.12a13.dist-info/METADATA,sha256=ysOxPQrER0dZJNEJH4ClVsP8CdZqhkHHqJnMsEAGjYI,4996
79
+ jararaca-0.3.12a13.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
80
+ jararaca-0.3.12a13.dist-info/entry_points.txt,sha256=WIh3aIvz8LwUJZIDfs4EeH3VoFyCGEk7cWJurW38q0I,45
81
+ jararaca-0.3.12a13.dist-info/RECORD,,
pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "jararaca"
3
- version = "0.3.12a11"
3
+ version = "0.3.12a13"
4
4
  description = "A simple and fast API framework for Python"
5
5
  authors = ["Lucas S <me@luscasleo.dev>"]
6
6
  readme = "README.md"