From 14db5d9425354ddad17bd109c8b10cbff8d6efe7 Mon Sep 17 00:00:00 2001 From: remittor Date: Sun, 29 Mar 2026 10:48:41 +0300 Subject: [PATCH 1/4] [python] FastPySGI: Add support static test --- frameworks/fastpysgi-asgi/app.py | 40 +++++++++++++++++++++++++-- frameworks/fastpysgi-asgi/meta.json | 3 ++- frameworks/fastpysgi/app.py | 42 ++++++++++++++++++++++++++--- frameworks/fastpysgi/meta.json | 3 ++- 4 files changed, 81 insertions(+), 7 deletions(-) diff --git a/frameworks/fastpysgi-asgi/app.py b/frameworks/fastpysgi-asgi/app.py index e5fde5a4..62ca81f2 100644 --- a/frameworks/fastpysgi-asgi/app.py +++ b/frameworks/fastpysgi-asgi/app.py @@ -6,6 +6,7 @@ import multiprocessing import zlib import sqlite3 +import mimetypes from urllib.parse import parse_qs import orjson @@ -15,6 +16,28 @@ CPU_COUNT = int(multiprocessing.cpu_count()) +STATIC_DIR = '/data/static/' +STATIC_FILES = { } +def load_static_files(): + global STATIC_FILES, STATIC_DIR + for root, dirs, files in os.walk(STATIC_DIR): + for filename in files: + full_path = os.path.join(root, filename) + rel_path = os.path.relpath(full_path, STATIC_DIR) + key = rel_path.replace(os.sep, '/') + try: + with open(full_path, 'rb') as file: + data = file.read() + except Exception as e: + continue + ext = os.path.splitext(filename)[1] + content_type, encoding = mimetypes.guess_type(full_path) + if content_type is None: + content_type = 'application/octet-stream' + STATIC_FILES[key] = (data, content_type.encode()) + +load_static_files() + DB_PATH = "/data/benchmark.db" DB_AVAILABLE = os.path.exists(DB_PATH) DB_QUERY = ( @@ -57,7 +80,7 @@ except Exception: pass -# -- SQLite (thread-local, sync — runs in threadpool via run_in_executor) -- +# -- SQLite (thread-local) -------------------------------------------------- _local = threading.local() @@ -254,6 +277,16 @@ async def async_db_endpoint(scope, receive, send): ] return json_resp( { "items": items, "count": len(items) } ) +async def static_file_endpoint(scope, receive, send): + global STATIC_FILES, STATIC_DIR + path = scope['path'] + filename = STATIC_DIR + path.removeprefix('/static/') + entry = STATIC_FILES.get(filename) + if entry is None: + return text_resp(b'Not found', status = 404) + data, ct = entry + return 200, [[ b'Content-Type', ct ]], data + async def upload_endpoint(scope, receive, send): size = 0 while True: @@ -306,7 +339,10 @@ async def app(scope, receive, send): await send( { 'type': 'http.response.body', 'body': b'Method Not Allowed', 'more_body': False } ) return path = scope['path'] - app_handler = ROUTES.get(path, handle_404) + if path.startswith('/static/'): + app_handler = static_file_endpoint + else: + app_handler = ROUTES.get(path, handle_404) status, headers, body = await app_handler(scope, receive, None) await send( { 'type': 'http.response.start', 'status': status, 'headers': headers } ) await send( { 'type': 'http.response.body', 'body': body, 'more_body': False } ) diff --git a/frameworks/fastpysgi-asgi/meta.json b/frameworks/fastpysgi-asgi/meta.json index 437fef8d..904c59df 100644 --- a/frameworks/fastpysgi-asgi/meta.json +++ b/frameworks/fastpysgi-asgi/meta.json @@ -15,6 +15,7 @@ "upload", "compression", "mixed", - "async-db" + "async-db", + "static" ] } diff --git a/frameworks/fastpysgi/app.py b/frameworks/fastpysgi/app.py index 135c6efe..09f7e5ec 100644 --- a/frameworks/fastpysgi/app.py +++ b/frameworks/fastpysgi/app.py @@ -5,6 +5,7 @@ import multiprocessing import zlib import sqlite3 +import mimetypes from urllib.parse import parse_qs import orjson @@ -15,6 +16,28 @@ CPU_COUNT = int(multiprocessing.cpu_count()) +STATIC_DIR = '/data/static/' +STATIC_FILES = { } +def load_static_files(): + global STATIC_FILES, STATIC_DIR + for root, dirs, files in os.walk(STATIC_DIR): + for filename in files: + full_path = os.path.join(root, filename) + rel_path = os.path.relpath(full_path, STATIC_DIR) + key = rel_path.replace(os.sep, '/') + try: + with open(full_path, 'rb') as file: + data = file.read() + except Exception as e: + continue + ext = os.path.splitext(filename)[1] + content_type, encoding = mimetypes.guess_type(full_path) + if content_type is None: + content_type = 'application/octet-stream' + STATIC_FILES[key] = (data, content_type) + +load_static_files() + DB_PATH = "/data/benchmark.db" DB_AVAILABLE = os.path.exists(DB_PATH) DB_QUERY = ( @@ -56,7 +79,7 @@ except Exception: pass -# -- SQLite (thread-local, sync — runs in threadpool via run_in_executor) -- +# -- SQLite (thread-local) -------------------------------------------------- _local = threading.local() @@ -230,6 +253,16 @@ def async_db_endpoint(env): except Exception: return json_resp( { "items": [ ], "count": 0 } ) +def static_file_endpoint(env): + global STATIC_FILES, STATIC_DIR + path = env["PATH_INFO"] + filename = STATIC_DIR + path.removeprefix('/static/') + entry = STATIC_FILES.get(filename) + if entry is None: + return text_resp(b'Not found', status = 404) + data, ct = entry + return 200, [ ('Content-Type', ct) ], data + READ_BUF_SIZE = 256*1024 @@ -280,8 +313,11 @@ def app(env, start_response): if req_method not in [ 'GET', 'POST' ]: status, headers, body = handle_405(env) else: - path = env["PATH_INFO"] - app_handler = ROUTES.get(path, handle_404) + path = env["PATH_INFO"] + if path.startswith('/static/'): + app_handler = static_file_endpoint + else: + app_handler = ROUTES.get(path, handle_404) status, headers, body = app_handler(env) start_response(HTTP_STATUS.get(status, str(status)), headers) return [ body ] diff --git a/frameworks/fastpysgi/meta.json b/frameworks/fastpysgi/meta.json index f08433b2..84ee2058 100644 --- a/frameworks/fastpysgi/meta.json +++ b/frameworks/fastpysgi/meta.json @@ -15,6 +15,7 @@ "upload", "compression", "mixed", - "async-db" + "async-db", + "static" ] } From c0b706e99f34bf4bf2502280c236e22062c5f4c1 Mon Sep 17 00:00:00 2001 From: remittor Date: Sun, 29 Mar 2026 11:19:55 +0300 Subject: [PATCH 2/4] [python] FastPySGI: Fix MIME types for static test --- frameworks/fastpysgi-asgi/app.py | 20 +++++++++++++++----- frameworks/fastpysgi/app.py | 20 +++++++++++++++----- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/frameworks/fastpysgi-asgi/app.py b/frameworks/fastpysgi-asgi/app.py index 62ca81f2..fc91a230 100644 --- a/frameworks/fastpysgi-asgi/app.py +++ b/frameworks/fastpysgi-asgi/app.py @@ -16,24 +16,34 @@ CPU_COUNT = int(multiprocessing.cpu_count()) +MIME_TYPES = { + '.css' : 'text/css', + '.js' : 'application/javascript', + '.html' : 'text/html', + '.woff2': 'font/woff2', + '.svg' : 'image/svg+xml', + '.webp' : 'image/webp', + '.json' : 'application/json', +} STATIC_DIR = '/data/static/' STATIC_FILES = { } def load_static_files(): - global STATIC_FILES, STATIC_DIR + global STATIC_FILES, STATIC_DIR, MIME_TYPES for root, dirs, files in os.walk(STATIC_DIR): for filename in files: full_path = os.path.join(root, filename) - rel_path = os.path.relpath(full_path, STATIC_DIR) - key = rel_path.replace(os.sep, '/') + key = full_path.replace(os.sep, '/') try: with open(full_path, 'rb') as file: data = file.read() except Exception as e: continue ext = os.path.splitext(filename)[1] - content_type, encoding = mimetypes.guess_type(full_path) + content_type = MIME_TYPES.get(ext) if content_type is None: - content_type = 'application/octet-stream' + content_type, encoding = mimetypes.guess_type(full_path) + if content_type is None: + content_type = 'application/octet-stream' STATIC_FILES[key] = (data, content_type.encode()) load_static_files() diff --git a/frameworks/fastpysgi/app.py b/frameworks/fastpysgi/app.py index 09f7e5ec..6352b65d 100644 --- a/frameworks/fastpysgi/app.py +++ b/frameworks/fastpysgi/app.py @@ -16,24 +16,34 @@ CPU_COUNT = int(multiprocessing.cpu_count()) +MIME_TYPES = { + '.css' : 'text/css', + '.js' : 'application/javascript', + '.html' : 'text/html', + '.woff2': 'font/woff2', + '.svg' : 'image/svg+xml', + '.webp' : 'image/webp', + '.json' : 'application/json', +} STATIC_DIR = '/data/static/' STATIC_FILES = { } def load_static_files(): - global STATIC_FILES, STATIC_DIR + global STATIC_FILES, STATIC_DIR, MIME_TYPES for root, dirs, files in os.walk(STATIC_DIR): for filename in files: full_path = os.path.join(root, filename) - rel_path = os.path.relpath(full_path, STATIC_DIR) - key = rel_path.replace(os.sep, '/') + key = full_path.replace(os.sep, '/') try: with open(full_path, 'rb') as file: data = file.read() except Exception as e: continue ext = os.path.splitext(filename)[1] - content_type, encoding = mimetypes.guess_type(full_path) + content_type = MIME_TYPES.get(ext) if content_type is None: - content_type = 'application/octet-stream' + content_type, encoding = mimetypes.guess_type(full_path) + if content_type is None: + content_type = 'application/octet-stream' STATIC_FILES[key] = (data, content_type) load_static_files() From 8d7b2acfc85958511098fbc226829bb1507fb205 Mon Sep 17 00:00:00 2001 From: remittor Date: Sun, 29 Mar 2026 11:25:15 +0300 Subject: [PATCH 3/4] [python] FastPySGI: Increase backlog to 16K --- frameworks/fastpysgi-asgi/app.py | 2 +- frameworks/fastpysgi/app.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frameworks/fastpysgi-asgi/app.py b/frameworks/fastpysgi-asgi/app.py index fc91a230..cb3ca112 100644 --- a/frameworks/fastpysgi-asgi/app.py +++ b/frameworks/fastpysgi-asgi/app.py @@ -366,6 +366,6 @@ async def app(scope, receive, send): port = 8080 fastpysgi.server.read_buffer_size = 256*1024 - fastpysgi.server.backlog = 4096 + fastpysgi.server.backlog = 16*1024 fastpysgi.server.loop_timeout = 1 fastpysgi.run(app, host, port, workers = CPU_COUNT, loglevel = 0) diff --git a/frameworks/fastpysgi/app.py b/frameworks/fastpysgi/app.py index 6352b65d..4419d9e9 100644 --- a/frameworks/fastpysgi/app.py +++ b/frameworks/fastpysgi/app.py @@ -341,5 +341,5 @@ def app(env, start_response): port = 8080 fastpysgi.server.read_buffer_size = READ_BUF_SIZE - fastpysgi.server.backlog = 4096 + fastpysgi.server.backlog = 16*1024 fastpysgi.run(app, host, port, workers = CPU_COUNT, loglevel = 0) From d91084edfc4dcbd4a6695d58fab442b5b622a161 Mon Sep 17 00:00:00 2001 From: remittor Date: Sun, 29 Mar 2026 12:50:22 +0300 Subject: [PATCH 4/4] [python] FastPySGI: Fix server worker count and delete pipelined test for ASGI --- frameworks/fastpysgi-asgi/app.py | 9 +++++---- frameworks/fastpysgi-asgi/meta.json | 1 - frameworks/fastpysgi/app.py | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/frameworks/fastpysgi-asgi/app.py b/frameworks/fastpysgi-asgi/app.py index cb3ca112..ba7ca8b0 100644 --- a/frameworks/fastpysgi-asgi/app.py +++ b/frameworks/fastpysgi-asgi/app.py @@ -15,6 +15,7 @@ # -- Dataset and constants -------------------------------------------------------- CPU_COUNT = int(multiprocessing.cpu_count()) +WRK_COUNT = min(len(os.sched_getaffinity(0)), 128) MIME_TYPES = { '.css' : 'text/css', @@ -107,7 +108,7 @@ def _get_db() -> sqlite3.Connection: # -- Postgres DB ------------------------------------------------------------ PG_POOL_MIN_SIZE = 2 -PG_POOL_MAX_SIZE = 3 +PG_POOL_MAX_SIZE = 2 class NoResetConnection(asyncpg.Connection): __slots__ = () @@ -124,7 +125,7 @@ async def db_close(): DATABASE_POOL = None async def db_setup(): - global DATABASE_POOL, DATABASE_URL, CPU_COUNT + global DATABASE_POOL, DATABASE_URL, WRK_COUNT await db_close() max_pool_size = 0 ''' @@ -140,7 +141,7 @@ async def db_setup(): pass if not max_connections: return - max_pool_size = int(max_connections * 0.87 / CPU_COUNT) + 1 + max_pool_size = int(max_connections * 0.87 / WRK_COUNT) + 1 ''' try: DATABASE_POOL = await asyncpg.create_pool( @@ -368,4 +369,4 @@ async def app(scope, receive, send): fastpysgi.server.read_buffer_size = 256*1024 fastpysgi.server.backlog = 16*1024 fastpysgi.server.loop_timeout = 1 - fastpysgi.run(app, host, port, workers = CPU_COUNT, loglevel = 0) + fastpysgi.run(app, host, port, workers = WRK_COUNT, loglevel = 0) diff --git a/frameworks/fastpysgi-asgi/meta.json b/frameworks/fastpysgi-asgi/meta.json index 904c59df..d69f31c5 100644 --- a/frameworks/fastpysgi-asgi/meta.json +++ b/frameworks/fastpysgi-asgi/meta.json @@ -8,7 +8,6 @@ "enabled": true, "tests": [ "baseline", - "pipelined", "noisy", "limited-conn", "json", diff --git a/frameworks/fastpysgi/app.py b/frameworks/fastpysgi/app.py index 4419d9e9..f66f8ec7 100644 --- a/frameworks/fastpysgi/app.py +++ b/frameworks/fastpysgi/app.py @@ -15,6 +15,7 @@ # -- Dataset and constants -------------------------------------------------------- CPU_COUNT = int(multiprocessing.cpu_count()) +WRK_COUNT = min(len(os.sched_getaffinity(0)), 128) MIME_TYPES = { '.css' : 'text/css', @@ -118,7 +119,7 @@ def db_close(): DATABASE_POOL = None def db_setup(): - global DATABASE_POOL, DATABASE_URL, CPU_COUNT + global DATABASE_POOL, DATABASE_URL, WRK_COUNT db_close() max_pool_size = 0 try: @@ -342,4 +343,4 @@ def app(env, start_response): fastpysgi.server.read_buffer_size = READ_BUF_SIZE fastpysgi.server.backlog = 16*1024 - fastpysgi.run(app, host, port, workers = CPU_COUNT, loglevel = 0) + fastpysgi.run(app, host, port, workers = WRK_COUNT, loglevel = 0)