Explorar o código

Upgrade Uvicorn (#3914)

* Upgrade Uvicorn

* Fix error in accessing queries attribute
Tom Christie %!s(int64=7) %!d(string=hai) anos
pai
achega
b69f8ba933

+ 192 - 92
frameworks/Python/uvicorn/app.py

@@ -52,115 +52,215 @@ def get_query_count(query_string):
 random_int = partial(randint, 1, 10000)
 random_int = partial(randint, 1, 10000)
 
 
 
 
-async def json_endpoint(message, channels):
-    content = json.dumps({'message': 'Hello, world!'}).encode('utf-8')
-    await channels['reply'].send({
-        'status': 200,
-        'headers': [
-            [b'content-type', b'application/json'],
-        ],
-        'content': content
-    })
-
-
-async def fortunes_endpoint(message, channels):
-    connection = await pool.acquire()
-    try:
-        fortunes = await connection.fetch('SELECT * FROM Fortune')
-        fortunes.append(additional)
-        fortunes.sort(key=key)
-        content = template.render(fortunes=fortunes).encode('utf-8')
-        await channels['reply'].send({
-            'status': 200,
-            'headers': [
-                [b'content-type', b'text/html; charset=utf-8'],
-            ],
-            'content': content
-        })
-    finally:
-        await pool.release(connection)
-
-
-async def plaintext_endpoint(message, channels):
-    await channels['reply'].send({
-        'status': 200,
-        'headers': [
-            [b'content-type', b'text/plain'],
-        ],
-        'content': b'Hello, world!'
-    })
-
-
-async def handle_404(message, channels):
-    await channels['reply'].send({
-        'status': 404,
-        'headers': [
-            [b'content-type', b'text/plain'],
-        ],
-        'content': b'Not found'
-    })
-
-
-async def db_endpoint(message, channels):
-    """Test Type 2: Single database object"""
-    async with pool.acquire() as connection:
-        row = await connection.fetchrow('SELECT id, "randomnumber" FROM "world" WHERE id = ' + str(random_int()))
-        world = {'id': row[0], 'randomNumber': row[1]}
-        await channels['reply'].send({
+class JSONSerialization:
+    """
+    Test type 1: JSON Serialization
+    """
+    def __init__(self, scope):
+        pass
+
+    async def __call__(self, receive, send):
+        content = json.dumps({'message': 'Hello, world!'}).encode('utf-8')
+        await send({
+            'type': 'http.response.start',
             'status': 200,
             'status': 200,
             'headers': [
             'headers': [
                 [b'content-type', b'application/json'],
                 [b'content-type', b'application/json'],
-            ],
-            'content': json.dumps(world).encode('utf-8')
+                [b'content-length', str(len(content)).encode()]
+            ]
         })
         })
+        await send({
+            'type': 'http.response.body',
+            'body': content,
+            'more_body': False
+        })
+
+
+class SingleDatabaseQuery:
+    """
+    Test type 2: Single database object
+    """
+    def __init__(self, scope):
+        pass
+
+    async def __call__(self, receive, send):
+        connection = await pool.acquire()
+        try:
+            row = await connection.fetchrow('SELECT id, "randomnumber" FROM "world" WHERE id = ' + str(random_int()))
+            world = {'id': row[0], 'randomNumber': row[1]}
+
+            content = json.dumps(world).encode('utf-8')
+            await send({
+                'type': 'http.response.start',
+                'status': 200,
+                'headers': [
+                    [b'content-type', b'application/json'],
+                    [b'content-length', str(len(content)).encode()]
+                ]
+            })
+            await send({
+                'type': 'http.response.body',
+                'body': content,
+                'more_body': False
+            })
+        finally:
+            await pool.release(connection)
+
+
+class MultipleDatabaseQueries:
+    """
+    Test type 3: Multiple database queries
+    """
+    def __init__(self, scope):
+        self.queries = get_query_count(scope.get('query_string', {}))
+
+    async def __call__(self, receive, send):
+        connection = await pool.acquire()
+        try:
+            worlds = []
+            for i in range(self.queries):
+                sql = 'SELECT id, "randomnumber" FROM "world" WHERE id = ' + str(random_int())
+                row = await connection.fetchrow(sql)
+                worlds.append({'id': row[0], 'randomNumber': row[1]})
+
+            content = json.dumps(worlds).encode('utf-8')
+            await send({
+                'type': 'http.response.start',
+                'status': 200,
+                'headers': [
+                    [b'content-type', b'application/json'],
+                    [b'content-length', str(len(content)).encode()]
+                ]
+            })
+            await send({
+                'type': 'http.response.body',
+                'body': content,
+                'more_body': False
+            })
+        finally:
+            await pool.release(connection)
 
 
 
 
-async def queries_endpoint(message, channels):
-    """Test Type 3: Multiple database queries"""
-    queries = get_query_count(message.get('query_string', {}))
-    async with pool.acquire() as connection:
-        worlds = []
-        for i in range(queries):
-            sql = 'SELECT id, "randomnumber" FROM "world" WHERE id = ' + str(random_int())
-            row = await connection.fetchrow(sql)
-            worlds.append({'id': row[0], 'randomNumber': row[1]})
-        await channels['reply'].send({
+class Fortunes:
+    """
+    Test type 4: Fortunes
+    """
+    def __init__(self, scope):
+        pass
+
+    async def __call__(self, receive, send):
+        connection = await pool.acquire()
+        try:
+            fortunes = await connection.fetch('SELECT * FROM Fortune')
+            fortunes.append(additional)
+            fortunes.sort(key=key)
+            content = template.render(fortunes=fortunes).encode('utf-8')
+            await send({
+                'type': 'http.response.start',
+                'status': 200,
+                'headers': [
+                    [b'content-type', b'text/html; charset=utf-8'],
+                    [b'content-length', str(len(content)).encode()]
+                ]
+            })
+            await send({
+                'type': 'http.response.body',
+                'body': content,
+                'more_body': False
+            })
+        finally:
+            await pool.release(connection)
+
+
+class DatabaseUpdates:
+    """
+    Test type 5: Database updates
+    """
+    def __init__(self, scope):
+        self.queries = get_query_count(scope.get('query_string', {}))
+
+    async def __call__(self, receive, send):
+        connection = await pool.acquire()
+        try:
+            worlds = []
+            for i in range(self.queries):
+                row = await connection.fetchrow('SELECT id FROM "world" WHERE id=' + str(random_int()))
+                worlds.append({'id': row[0], 'randomNumber': random_int()})
+                await connection.execute('UPDATE "world" SET "randomnumber"=%s WHERE id=%s' % (random_int(), row[0]))
+
+            content = json.dumps(worlds).encode('utf-8')
+            await send({
+                'type': 'http.response.start',
+                'status': 200,
+                'headers': [
+                    [b'content-type', b'application/json'],
+                    [b'content-length', str(len(content)).encode()]
+                ]
+            })
+            await send({
+                'type': 'http.response.body',
+                'body': content,
+                'more_body': False
+            })
+        finally:
+            await pool.release(connection)
+
+
+class Plaintext:
+    """
+    Test type 6: Plaintext
+    """
+    def __init__(self, scope):
+        pass
+
+    async def __call__(self, receive, send):
+        content = b'Hello, world!'
+        await send({
+            'type': 'http.response.start',
             'status': 200,
             'status': 200,
             'headers': [
             'headers': [
-                [b'content-type', b'application/json'],
-            ],
-            'content': json.dumps(worlds).encode('utf-8')
+                [b'content-type', b'text/plain'],
+                [b'content-length', str(len(content)).encode()]
+            ]
+        })
+        await send({
+            'type': 'http.response.body',
+            'body': content,
+            'more_body': False
         })
         })
 
 
 
 
-async def updates_endpoint(message, channels):
-    """Test 5: Database Updates"""
-    queries = get_query_count(message.get('query_string', {}))
-    async with pool.acquire() as connection:
-        worlds = []
-        for i in range(queries):
-            row = await connection.fetchrow('SELECT id FROM "world" WHERE id=' + str(random_int()))
-            worlds.append({'id': row[0], 'randomNumber': random_int()})
-            await connection.execute('UPDATE "world" SET "randomnumber"=%s WHERE id=%s' % (random_int(), row[0]))
-        await channels['reply'].send({
+class Handle404:
+    def __init__(self, scope):
+        pass
+
+    async def __call__(self, receive, send):
+        content = b'Not found'
+        await send({
+            'type': 'http.response.start',
             'status': 200,
             'status': 200,
             'headers': [
             'headers': [
-                [b'content-type', b'application/json'],
-            ],
-            'content': json.dumps(worlds).encode('utf-8')
+                [b'content-type', b'text/plain'],
+                [b'content-length', str(len(content)).encode()]
+            ]
+        })
+        await send({
+            'type': 'http.response.body',
+            'body': content,
+            'more_body': False
         })
         })
 
 
 
 
 routes = {
 routes = {
-    '/json': json_endpoint,
-    '/fortunes': fortunes_endpoint,
-    '/plaintext': plaintext_endpoint,
-    '/db': db_endpoint,
-    '/queries': queries_endpoint,
-    '/updates': updates_endpoint,
+    '/json': JSONSerialization,
+    '/db': SingleDatabaseQuery,
+    '/queries': MultipleDatabaseQueries,
+    '/fortunes': Fortunes,
+    '/updates': DatabaseUpdates,
+    '/plaintext': Plaintext,
 }
 }
 
 
 
 
-async def main(message, channels):
-    path = message['path']
-    await routes.get(path, handle_404)(message, channels)
+def main(scope):
+    path = scope['path']
+    return routes.get(path, Handle404)(scope)

+ 4 - 3
frameworks/Python/uvicorn/requirements.txt

@@ -1,4 +1,5 @@
-asyncpg==0.11.0
-jinja2==2.9.6
+asyncpg==0.16.0
+jinja2==2.10
 ujson==1.35
 ujson==1.35
-uvicorn==0.0.13
+uvicorn==0.2.7
+gunicorn==19.9.0

+ 1 - 1
frameworks/Python/uvicorn/uvicorn.dockerfile

@@ -6,4 +6,4 @@ WORKDIR /uvicorn
 
 
 RUN pip3 install -r /uvicorn/requirements.txt
 RUN pip3 install -r /uvicorn/requirements.txt
 
 
-CMD uvicorn app:main -c uvicorn_conf.py
+CMD gunicorn app:main -k uvicorn.workers.UvicornWorker -c uvicorn_conf.py

+ 1 - 0
frameworks/Python/uvicorn/uvicorn_conf.py

@@ -11,3 +11,4 @@ bind = "0.0.0.0:8080"
 keepalive = 120
 keepalive = 120
 errorlog = '-'
 errorlog = '-'
 pidfile = '/tmp/uvicorn.pid'
 pidfile = '/tmp/uvicorn.pid'
+loglevel = 'error'