Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions frameworks/django/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
ENV DJANGO_SETTINGS_MODULE=settings
EXPOSE 8080
CMD ["gunicorn", "-c", "gunicorn_conf.py", "wsgi:application"]
5 changes: 5 additions & 0 deletions frameworks/django/gunicorn_conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import os

bind = '0.0.0.0:8080'
workers = len(os.sched_getaffinity(0)) * 2
keepalive = 120
19 changes: 19 additions & 0 deletions frameworks/django/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"display_name": "Django",
"language": "Python",
"type": "framework",
"engine": "gunicorn",
"description": "Django web framework on Gunicorn with sync workers, one worker per CPU core.",
"repo": "https://github.com/django/django",
"enabled": true,
"tests": [
"baseline",
"pipelined",
"noisy",
"limited-conn",
"json",
"upload",
"compression",
"mixed"
]
}
2 changes: 2 additions & 0 deletions frameworks/django/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
django==5.2
gunicorn==23.0.0
8 changes: 8 additions & 0 deletions frameworks/django/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
SECRET_KEY = 'httparena-benchmark'
DEBUG = False
ALLOWED_HOSTS = ['*']
INSTALLED_APPS = []
MIDDLEWARE = []
ROOT_URLCONF = 'urls'
USE_TZ = False
LOGGING_CONFIG = None
12 changes: 12 additions & 0 deletions frameworks/django/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django.urls import path
from views import pipeline, baseline11, baseline2, json_endpoint, compression_endpoint, db_endpoint, upload_endpoint

urlpatterns = [
path('pipeline', pipeline),
path('baseline11', baseline11),
path('baseline2', baseline2),
path('json', json_endpoint),
path('compression', compression_endpoint),
path('db', db_endpoint),
path('upload', upload_endpoint),
]
152 changes: 152 additions & 0 deletions frameworks/django/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import json
import os
import gzip
import sqlite3
import threading
from django.http import HttpResponse, HttpResponseNotAllowed
from django.views.decorators.http import require_http_methods, require_GET

# Load raw dataset for per-request processing
dataset_items = None
dataset_path = os.environ.get('DATASET_PATH', '/data/dataset.json')
try:
with open(dataset_path) as f:
dataset_items = json.load(f)
except Exception:
pass

# Large dataset for compression — pre-compute JSON and gzip
large_json_buf = None
large_gzip_buf = None
try:
with open('/data/dataset-large.json') as f:
raw = json.load(f)
items = []
for d in raw:
item = dict(d)
item['total'] = round(d['price'] * d['quantity'] * 100) / 100
items.append(item)
large_json_buf = json.dumps({'items': items, 'count': len(items)}).encode()
large_gzip_buf = gzip.compress(large_json_buf, compresslevel=1)
except Exception:
pass

# Pre-compute JSON response for /json endpoint
json_response_buf = None
if dataset_items:
items = []
for d in dataset_items:
item = dict(d)
item['total'] = round(d['price'] * d['quantity'] * 100) / 100
items.append(item)
json_response_buf = json.dumps({'items': items, 'count': len(items)}).encode()

# SQLite
db_available = os.path.exists('/data/benchmark.db')
DB_QUERY = 'SELECT id, name, category, price, quantity, active, tags, rating_score, rating_count FROM items WHERE price BETWEEN ? AND ? LIMIT 50'

_local = threading.local()

def get_db():
if not hasattr(_local, 'conn'):
_local.conn = sqlite3.connect('/data/benchmark.db', uri=True)
_local.conn.execute('PRAGMA mmap_size=268435456')
_local.conn.row_factory = sqlite3.Row
return _local.conn


@require_GET
def pipeline(request):
resp = HttpResponse(b'ok', content_type='text/plain')
resp['Server'] = 'django'
return resp


@require_http_methods(["GET", "POST"])
def baseline11(request):
total = 0
for v in request.GET.values():
try:
total += int(v)
except ValueError:
pass
if request.method == 'POST':
# Read from wsgi.input directly to handle chunked Transfer-Encoding
# (Django's request.body checks CONTENT_LENGTH which is absent for chunked)
content_length = request.META.get('CONTENT_LENGTH')
if content_length:
body = request.body
else:
body = request.META['wsgi.input'].read()
if body:
try:
total += int(body.strip())
except ValueError:
pass
resp = HttpResponse(str(total), content_type='text/plain')
resp['Server'] = 'django'
return resp


@require_GET
def baseline2(request):
total = 0
for v in request.GET.values():
try:
total += int(v)
except ValueError:
pass
resp = HttpResponse(str(total), content_type='text/plain')
resp['Server'] = 'django'
return resp


@require_GET
def json_endpoint(request):
if json_response_buf:
resp = HttpResponse(json_response_buf, content_type='application/json')
resp['Server'] = 'django'
return resp
return HttpResponse('No dataset', status=500)


@require_GET
def compression_endpoint(request):
if large_gzip_buf:
resp = HttpResponse(large_gzip_buf, content_type='application/json')
resp['Content-Encoding'] = 'gzip'
resp['Server'] = 'django'
return resp
return HttpResponse('No dataset', status=500)


@require_GET
def db_endpoint(request):
if not db_available:
resp = HttpResponse(b'{"items":[],"count":0}', content_type='application/json')
resp['Server'] = 'django'
return resp
min_val = float(request.GET.get('min', 10))
max_val = float(request.GET.get('max', 50))
conn = get_db()
rows = conn.execute(DB_QUERY, (min_val, max_val)).fetchall()
items = []
for r in rows:
items.append({
'id': r['id'], 'name': r['name'], 'category': r['category'],
'price': r['price'], 'quantity': r['quantity'], 'active': bool(r['active']),
'tags': json.loads(r['tags']),
'rating': {'score': r['rating_score'], 'count': r['rating_count']}
})
body = json.dumps({'items': items, 'count': len(items)})
resp = HttpResponse(body, content_type='application/json')
resp['Server'] = 'django'
return resp


@require_http_methods(["POST"])
def upload_endpoint(request):
data = request.body
resp = HttpResponse(str(len(data)), content_type='text/plain')
resp['Server'] = 'django'
return resp
5 changes: 5 additions & 0 deletions frameworks/django/wsgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
Loading