@vercel/python 4.4.1 → 4.5.1

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 (2) hide show
  1. package/package.json +1 -1
  2. package/vc_init.py +64 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/python",
3
- "version": "4.4.1",
3
+ "version": "4.5.1",
4
4
  "main": "./dist/index.js",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
package/vc_init.py CHANGED
@@ -43,6 +43,49 @@ if 'VERCEL_IPC_FD' in os.environ:
43
43
  send_message = lambda message: sock.sendall((json.dumps(message) + '\0').encode())
44
44
  storage = contextvars.ContextVar('storage', default=None)
45
45
 
46
+ # Override urlopen from urllib3 (& requests) to send Request Metrics
47
+ try:
48
+ import urllib3
49
+ from urllib.parse import urlparse
50
+
51
+ def timed_request(func):
52
+ fetchId = 0
53
+ @functools.wraps(func)
54
+ def wrapper(self, method, url, *args, **kwargs):
55
+ nonlocal fetchId
56
+ fetchId += 1
57
+ start_time = int(time.time() * 1000)
58
+ result = func(self, method, url, *args, **kwargs)
59
+ elapsed_time = int(time.time() * 1000) - start_time
60
+ parsed_url = urlparse(url)
61
+ context = storage.get()
62
+ if context is not None:
63
+ send_message({
64
+ "type": "metric",
65
+ "payload": {
66
+ "context": {
67
+ "invocationId": context['invocationId'],
68
+ "requestId": context['requestId'],
69
+ },
70
+ "type": "fetch-metric",
71
+ "payload": {
72
+ "pathname": parsed_url.path,
73
+ "search": parsed_url.query,
74
+ "start": start_time,
75
+ "duration": elapsed_time,
76
+ "host": parsed_url.hostname or self.host,
77
+ "statusCode": result.status,
78
+ "method": method,
79
+ "id": fetchId
80
+ }
81
+ }
82
+ })
83
+ return result
84
+ return wrapper
85
+ urllib3.connectionpool.HTTPConnectionPool.urlopen = timed_request(urllib3.connectionpool.HTTPConnectionPool.urlopen)
86
+ except:
87
+ pass
88
+
46
89
  # Override sys.stdout and sys.stderr to map logs to the correct request
47
90
  class StreamWrapper:
48
91
  def __init__(self, stream, stream_name):
@@ -276,21 +319,23 @@ if 'VERCEL_IPC_FD' in os.environ:
276
319
  'raw_path': url.path.encode(),
277
320
  }
278
321
 
322
+ if 'content-length' in self.headers:
323
+ content_length = int(self.headers['content-length'])
324
+ body = self.rfile.read(content_length)
325
+ else:
326
+ body = b''
327
+
328
+ if _use_legacy_asyncio:
329
+ loop = asyncio.new_event_loop()
330
+ app_queue = asyncio.Queue(loop=loop)
331
+ else:
332
+ app_queue = asyncio.Queue()
333
+ app_queue.put_nowait({'type': 'http.request', 'body': body, 'more_body': False})
334
+
279
335
  # Prepare ASGI receive function
280
336
  async def receive():
281
- if 'content-length' in self.headers:
282
- content_length = int(self.headers['content-length'])
283
- body = self.rfile.read(content_length)
284
- return {
285
- 'type': 'http.request',
286
- 'body': body,
287
- 'more_body': False,
288
- }
289
- return {
290
- 'type': 'http.request',
291
- 'body': b'',
292
- 'more_body': False,
293
- }
337
+ message = await app_queue.get()
338
+ return message
294
339
 
295
340
  # Prepare ASGI send function
296
341
  response_started = False
@@ -309,7 +354,12 @@ if 'VERCEL_IPC_FD' in os.environ:
309
354
  self.wfile.flush()
310
355
 
311
356
  # Run the ASGI application
312
- asyncio.run(app(scope, receive, send))
357
+ asgi_instance = app(scope, receive, send)
358
+ if _use_legacy_asyncio:
359
+ asgi_task = loop.create_task(asgi_instance)
360
+ loop.run_until_complete(asgi_task)
361
+ else:
362
+ asyncio.run(asgi_instance)
313
363
 
314
364
  if 'Handler' in locals():
315
365
  server = ThreadingHTTPServer(('127.0.0.1', 0), Handler)