zenx 0.9.8__tar.gz → 0.10.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.
Files changed (33) hide show
  1. {zenx-0.9.8 → zenx-0.10.0}/PKG-INFO +1 -1
  2. {zenx-0.9.8 → zenx-0.10.0}/pyproject.toml +1 -1
  3. {zenx-0.9.8 → zenx-0.10.0}/zenx/clients/http.py +34 -13
  4. {zenx-0.9.8 → zenx-0.10.0}/zenx/utils.py +4 -0
  5. {zenx-0.9.8 → zenx-0.10.0}/zenx.egg-info/PKG-INFO +1 -1
  6. {zenx-0.9.8 → zenx-0.10.0}/README.md +0 -0
  7. {zenx-0.9.8 → zenx-0.10.0}/setup.cfg +0 -0
  8. {zenx-0.9.8 → zenx-0.10.0}/zenx/cli.py +0 -0
  9. {zenx-0.9.8 → zenx-0.10.0}/zenx/clients/__init__.py +0 -0
  10. {zenx-0.9.8 → zenx-0.10.0}/zenx/clients/database.py +0 -0
  11. {zenx-0.9.8 → zenx-0.10.0}/zenx/debug_runner.py +0 -0
  12. {zenx-0.9.8 → zenx-0.10.0}/zenx/discovery.py +0 -0
  13. {zenx-0.9.8 → zenx-0.10.0}/zenx/engine.py +0 -0
  14. {zenx-0.9.8 → zenx-0.10.0}/zenx/exceptions.py +0 -0
  15. {zenx-0.9.8 → zenx-0.10.0}/zenx/logger.py +0 -0
  16. {zenx-0.9.8 → zenx-0.10.0}/zenx/pipelines/__init__.py +0 -0
  17. {zenx-0.9.8 → zenx-0.10.0}/zenx/pipelines/base.py +0 -0
  18. {zenx-0.9.8 → zenx-0.10.0}/zenx/pipelines/discord.py +0 -0
  19. {zenx-0.9.8 → zenx-0.10.0}/zenx/pipelines/google_rpc.py +0 -0
  20. {zenx-0.9.8 → zenx-0.10.0}/zenx/pipelines/manager.py +0 -0
  21. {zenx-0.9.8 → zenx-0.10.0}/zenx/pipelines/preprocess.py +0 -0
  22. {zenx-0.9.8 → zenx-0.10.0}/zenx/pipelines/websocket.py +0 -0
  23. {zenx-0.9.8 → zenx-0.10.0}/zenx/resources/proto/__init__.py +0 -0
  24. {zenx-0.9.8 → zenx-0.10.0}/zenx/resources/proto/feed_pb2.py +0 -0
  25. {zenx-0.9.8 → zenx-0.10.0}/zenx/resources/proto/feed_pb2_grpc.py +0 -0
  26. {zenx-0.9.8 → zenx-0.10.0}/zenx/settings.py +0 -0
  27. {zenx-0.9.8 → zenx-0.10.0}/zenx/spiders/__init__.py +0 -0
  28. {zenx-0.9.8 → zenx-0.10.0}/zenx/spiders/base.py +0 -0
  29. {zenx-0.9.8 → zenx-0.10.0}/zenx.egg-info/SOURCES.txt +0 -0
  30. {zenx-0.9.8 → zenx-0.10.0}/zenx.egg-info/dependency_links.txt +0 -0
  31. {zenx-0.9.8 → zenx-0.10.0}/zenx.egg-info/entry_points.txt +0 -0
  32. {zenx-0.9.8 → zenx-0.10.0}/zenx.egg-info/requires.txt +0 -0
  33. {zenx-0.9.8 → zenx-0.10.0}/zenx.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zenx
3
- Version: 0.9.8
3
+ Version: 0.10.0
4
4
  Summary: mini-framework
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: curl-cffi>=0.12.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "zenx"
3
- version = "0.9.8"
3
+ version = "0.10.0"
4
4
  description = "mini-framework"
5
5
  requires-python = ">=3.12"
6
6
  dependencies = [
@@ -12,7 +12,13 @@ import orjson
12
12
  from structlog import BoundLogger
13
13
 
14
14
  from zenx.settings import Settings
15
- from zenx.utils import get_time
15
+ from zenx.utils import get_time, get_uuid
16
+
17
+ @dataclass
18
+ class SessionWrapper:
19
+ id: str
20
+ requests: int
21
+ _self: AsyncSession
16
22
 
17
23
 
18
24
  @dataclass
@@ -91,15 +97,24 @@ class CurlCffi(HttpClient):
91
97
  self._session_pool = asyncio.Queue(maxsize=settings.SESSION_POOL_SIZE)
92
98
  for _ in range(settings.SESSION_POOL_SIZE):
93
99
  impersonate = self._get_random_fingerprint()
94
- self._session_pool.put_nowait(AsyncSession(max_clients=1, impersonate=impersonate))
100
+ obj = SessionWrapper(id=get_uuid(), requests=0, _self=AsyncSession(max_clients=1, impersonate=impersonate))
101
+ self._session_pool.put_nowait(obj)
95
102
  self.logger.debug("created", sessions=self._session_pool.qsize(), client=self.name)
96
103
 
97
104
 
98
105
  def _get_random_fingerprint(self) -> str:
99
106
  chosen_fingerprint = random.choice(self._fingerprints)
100
107
  return chosen_fingerprint
101
-
102
108
 
109
+
110
+ async def _replace_session(self, existing_session: SessionWrapper) -> None:
111
+ self.logger.debug("discarded", session_id=existing_session.id, requests=existing_session.requests, client=self.name)
112
+ await existing_session._self.close()
113
+ obj = SessionWrapper(id=get_uuid(), requests=0, _self=AsyncSession(max_clients=1, impersonate=self._get_random_fingerprint()))
114
+ self._session_pool.put_nowait(obj)
115
+ self.logger.debug("replaced", old_session=existing_session.id, new_session=obj.id, client=self.name)
116
+
117
+
103
118
  async def request(
104
119
  self,
105
120
  url: str,
@@ -139,11 +154,11 @@ class CurlCffi(HttpClient):
139
154
  # each session has its own fingerprint set
140
155
  kwargs.pop("impersonate", None)
141
156
  self.logger.debug("acquire_session", client=self.name)
142
- session: AsyncSession = await self._session_pool.get()
143
- self.logger.debug("acquired_session", impersonate=session.impersonate, client=self.name)
157
+ session_wrapper: SessionWrapper = await self._session_pool.get()
158
+ self.logger.debug("acquired_session", session_id=session_wrapper.id, client=self.name)
144
159
  try:
145
160
  req_at = get_time()
146
- response: CurlResponse = await asyncio.wait_for(session.request(
161
+ response: CurlResponse = await asyncio.wait_for(session_wrapper._self.request(
147
162
  url=url,
148
163
  method=method,
149
164
  headers=headers,
@@ -153,15 +168,21 @@ class CurlCffi(HttpClient):
153
168
  ), timeout=10)
154
169
  recv_at = get_time()
155
170
  latency = recv_at - req_at
156
- self.logger.debug("response", status=response.status_code, url=url, impersonate=session.impersonate, client=self.name, requested_at=req_at, responded_at=recv_at, latency_ms=latency)
171
+ session_wrapper.requests +=1
172
+ self.logger.debug("response", status=response.status_code, url=url, session_id=session_wrapper.id, requests=session_wrapper.requests, client=self.name, requested_at=req_at, responded_at=recv_at, latency_ms=latency)
157
173
  except TimeoutError:
158
- self.logger.error("timeout", url=url, impersonate=session.impersonate, client=self.name)
174
+ self.logger.error("timeout", url=url, client=self.name)
175
+ await self._replace_session(session_wrapper)
159
176
  raise
160
177
  except Exception:
161
- self.logger.exception("request", url=url, client=self.name)
178
+ self.logger.error("request", url=url, client=self.name)
179
+ await self._replace_session(session_wrapper)
162
180
  raise
163
- finally:
164
- self._session_pool.put_nowait(session)
181
+ else:
182
+ if response.status_code != 200:
183
+ await self._replace_session(session_wrapper)
184
+ else:
185
+ self._session_pool.put_nowait(session_wrapper)
165
186
 
166
187
  return Response(
167
188
  url=response.url,
@@ -178,6 +199,6 @@ class CurlCffi(HttpClient):
178
199
  count = self._session_pool.qsize()
179
200
  async with asyncio.TaskGroup() as tg:
180
201
  while not self._session_pool.empty():
181
- session: AsyncSession = await self._session_pool.get()
182
- tg.create_task(session.close())
202
+ session_wrapper: SessionWrapper = await self._session_pool.get()
203
+ tg.create_task(session_wrapper._self.close())
183
204
  self.logger.debug("closed", sessions=count, client=self.name)
@@ -1,4 +1,5 @@
1
1
  import time
2
+ import uuid
2
3
  from typing import Dict
3
4
  import functools
4
5
 
@@ -19,3 +20,6 @@ def log_processing_time(func):
19
20
  return result
20
21
  return wrapper
21
22
 
23
+
24
+ def get_uuid() -> str:
25
+ return uuid.uuid4().hex
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: zenx
3
- Version: 0.9.8
3
+ Version: 0.10.0
4
4
  Summary: mini-framework
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: curl-cffi>=0.12.0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes