hypha-rpc 0.20.89__py3-none-any.whl → 0.20.91__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.
hypha_rpc/VERSION CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "0.20.89"
2
+ "version": "0.20.91"
3
3
  }
hypha_rpc/http_client.py CHANGED
@@ -89,6 +89,7 @@ class HTTPStreamingRPCConnection:
89
89
  self._closed = False
90
90
  self._enable_reconnect = False
91
91
  self._stream_task: Optional[asyncio.Task] = None
92
+ self._refresh_token_task: Optional[asyncio.Task] = None
92
93
  self._http_client: Optional[httpx.AsyncClient] = None
93
94
 
94
95
  self.connection_info = None
@@ -108,6 +109,41 @@ class HTTPStreamingRPCConnection:
108
109
  self._handle_connected = handler
109
110
  assert inspect.iscoroutinefunction(handler), "Handler must be async"
110
111
 
112
+ async def _send_refresh_token(self, token_refresh_interval: float):
113
+ """Send refresh token request at regular intervals.
114
+
115
+ Similar to WebSocket, this periodically requests a new reconnection token
116
+ to keep the session alive and allow reconnection with a fresh token.
117
+ """
118
+ try:
119
+ await asyncio.sleep(2) # Initial delay
120
+ while not self._closed and self._http_client:
121
+ try:
122
+ # Send refresh token request via POST
123
+ workspace = self._workspace or "public"
124
+ url = f"{self._server_url}/{workspace}/rpc"
125
+ params = {"client_id": self._client_id}
126
+
127
+ refresh_message = msgpack.packb({"type": "refresh_token"})
128
+ response = await self._http_client.post(
129
+ url,
130
+ content=refresh_message,
131
+ params=params,
132
+ headers=self._get_headers(),
133
+ )
134
+ if response.status_code == 200:
135
+ logger.debug("Token refresh requested successfully")
136
+ else:
137
+ logger.warning(f"Token refresh request failed: {response.status_code}")
138
+ except Exception as e:
139
+ logger.warning(f"Failed to send refresh token request: {e}")
140
+
141
+ await asyncio.sleep(token_refresh_interval)
142
+ except asyncio.CancelledError:
143
+ logger.debug("Token refresh task was cancelled")
144
+ except Exception as e:
145
+ logger.error(f"Error in token refresh task: {e}")
146
+
111
147
  def _get_headers(self, for_stream: bool = False) -> dict:
112
148
  """Get HTTP headers with authentication.
113
149
 
@@ -163,6 +199,11 @@ class HTTPStreamingRPCConnection:
163
199
  if self._format == "msgpack":
164
200
  params["format"] = "msgpack"
165
201
 
202
+ # Add reconnection token if available (for reconnection)
203
+ if self._reconnection_token:
204
+ params["reconnection_token"] = self._reconnection_token
205
+ logger.info(f"Using reconnection token for HTTP streaming connection")
206
+
166
207
  try:
167
208
  # Start streaming in background task
168
209
  self._stream_task = asyncio.create_task(
@@ -190,11 +231,27 @@ class HTTPStreamingRPCConnection:
190
231
  if "reconnection_token" in self.connection_info:
191
232
  self._reconnection_token = self.connection_info["reconnection_token"]
192
233
 
234
+ # Adjust token refresh interval based on server's token lifetime
235
+ if "reconnection_token_life_time" in self.connection_info:
236
+ token_life_time = self.connection_info["reconnection_token_life_time"]
237
+ if self._token_refresh_interval > token_life_time / 1.5:
238
+ logger.warning(
239
+ f"Token refresh interval ({self._token_refresh_interval}s) is too long, "
240
+ f"adjusting to {token_life_time / 1.5:.0f}s based on token lifetime"
241
+ )
242
+ self._token_refresh_interval = token_life_time / 1.5
243
+
193
244
  logger.info(
194
245
  f"HTTP streaming connected to workspace: {self._workspace}, "
195
246
  f"manager_id: {self.manager_id}"
196
247
  )
197
248
 
249
+ # Start token refresh task
250
+ if self._token_refresh_interval > 0:
251
+ self._refresh_token_task = asyncio.create_task(
252
+ self._send_refresh_token(self._token_refresh_interval)
253
+ )
254
+
198
255
  if self._handle_connected:
199
256
  await self._handle_connected(self.connection_info)
200
257
 
@@ -400,6 +457,16 @@ class HTTPStreamingRPCConnection:
400
457
 
401
458
  async def _cleanup(self):
402
459
  """Cleanup resources."""
460
+ # Cancel token refresh task
461
+ if self._refresh_token_task and not self._refresh_token_task.done():
462
+ self._refresh_token_task.cancel()
463
+ try:
464
+ await asyncio.wait_for(self._refresh_token_task, timeout=1.0)
465
+ except (asyncio.CancelledError, asyncio.TimeoutError):
466
+ pass
467
+ self._refresh_token_task = None
468
+
469
+ # Cancel stream task
403
470
  if self._stream_task and not self._stream_task.done():
404
471
  self._stream_task.cancel()
405
472
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hypha_rpc
3
- Version: 0.20.89
3
+ Version: 0.20.91
4
4
  Summary: Hypha RPC client for connecting to Hypha server for data management and AI model serving
5
5
  Author-email: Wei Ouyang <oeway007@gmail.com>
6
6
  Requires-Python: >=3.9
@@ -1,7 +1,7 @@
1
- hypha_rpc/VERSION,sha256=vpnrMBAiB3l6wEQDy9_zHUIqw7t3BxjiItBOfzE1WXU,26
1
+ hypha_rpc/VERSION,sha256=j1kFO_lywKnDlLe-woiBFEziTNuwai-qeVyGIhLgkhY,26
2
2
  hypha_rpc/__init__.py,sha256=Nm01vho0uIMXET8-lqxaWTRgoKQD-0SEhpmS9odRed0,4721
3
3
  hypha_rpc/client.py,sha256=9c3Qd1bboNiEc_5P4jRLi233VFHyyME8alZYZ5ZZq6s,4551
4
- hypha_rpc/http_client.py,sha256=xdMhU64kte2T7uPVtwzRRWKOnYB_wRTCVg0qKzLllh8,20285
4
+ hypha_rpc/http_client.py,sha256=z1fbomvF9wk7ZxFmzfw8qnheE_ueXrg1C4c8Ss5hgWU,23545
5
5
  hypha_rpc/pyodide_sse.py,sha256=o1-6Bqb7bcplSy7pwkmtQb6vKeJsyxex_RebqNd3wX8,2960
6
6
  hypha_rpc/pyodide_websocket.py,sha256=XjrgKYySUSNYma-rXjHrSv08YCxj5t4hYEQnK15D6cE,18749
7
7
  hypha_rpc/rpc.py,sha256=lnNiPAm_BNT5JjDhAPFRlxs6HioXw77TelUtYd_blYk,115579
@@ -14,7 +14,7 @@ hypha_rpc/utils/mcp.py,sha256=AW48yjCovc0jyekRLeD_1U8mRaA8-nEqh4DotSE_s3Y,17348
14
14
  hypha_rpc/utils/pydantic.py,sha256=a09_ys4BSXc4Yi6OgZjdspbtLvQVoRCChr6uInY4fN4,5144
15
15
  hypha_rpc/utils/schema.py,sha256=WabBJiDheMKRXUroVe9JRlI5P4Wlv6kc0roxVNQZHH8,22110
16
16
  hypha_rpc/utils/serve.py,sha256=xr_3oAQDyignQbz1fcm4kuRMBOb52-i0VSYCjZou51c,11882
17
- hypha_rpc-0.20.89.dist-info/METADATA,sha256=Kybx_aqgy8mSAGioAlrqRJHmnjJwn29rcer8V5lBpV0,924
18
- hypha_rpc-0.20.89.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
19
- hypha_rpc-0.20.89.dist-info/top_level.txt,sha256=uShPbaPGP-Ig8OVnQcT6sEzV0Qhb6wfxSJ3uCmYaB58,10
20
- hypha_rpc-0.20.89.dist-info/RECORD,,
17
+ hypha_rpc-0.20.91.dist-info/METADATA,sha256=rIb0SqctYBNrj2IrRKSUBj2UBhAP1VFFECVRsScmAeg,924
18
+ hypha_rpc-0.20.91.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
19
+ hypha_rpc-0.20.91.dist-info/top_level.txt,sha256=uShPbaPGP-Ig8OVnQcT6sEzV0Qhb6wfxSJ3uCmYaB58,10
20
+ hypha_rpc-0.20.91.dist-info/RECORD,,