Skip to content

Commit 3988dba

Browse files
committed
gunicorn fix
1 parent 06b5774 commit 3988dba

File tree

6 files changed

+73
-10
lines changed

6 files changed

+73
-10
lines changed

.github/workflows/docker-build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: Docker Build and Push
22

33
on:
44
push:
5-
branches: [ main, master ]
5+
branches: [ main, master, gunicorn-fix ]
66
pull_request:
7-
branches: [ main, master ]
7+
branches: [ main, master, gunicorn-fix ]
88

99
env:
1010
SERVIZIO_OC: oc_sparql

Dockerfile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,10 @@ EXPOSE 8080
3333

3434
# Start the application
3535
# The Python script will now read environment variables for SPARQL configurations
36-
CMD ["python3", "sparql_oc.py"]
36+
CMD ["gunicorn", \
37+
"-w", "2", \
38+
"--worker-class", "gevent", \
39+
"--worker-connections", "800", \
40+
"--timeout", "1200", \
41+
"-b", "0.0.0.0:8080", \
42+
"sparql_oc:application"]

README.md

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ When static sync is enabled (via `--sync-static` or `SYNC_ENABLED=true`), the ap
7373
7474
## Running Options
7575

76+
### Local Development
77+
78+
For local development and testing, the application uses the built-in web.py HTTP server.
79+
7680
The application supports the following command line arguments:
7781

7882
- `--sync-static`: Synchronize static files at startup and enable periodic sync (every 30 minutes)
@@ -95,6 +99,20 @@ python3 sparql_oc.py --sync-static --port 8085
9599

96100
The Docker container is configured to run with `--sync-static` enabled by default.
97101

102+
### Production Deployment (Docker)
103+
104+
When running in Docker/Kubernetes, the application uses **Gunicorn** as the WSGI HTTP server for better performance and concurrency handling:
105+
106+
- **Server**: Gunicorn with gevent workers
107+
- **Workers**: 2 concurrent worker processes
108+
- **Worker Type**: gevent (async) for handling thousands of simultaneous requests
109+
- **Timeout**: 1200 seconds (to handle long-running SPARQL queries)
110+
- **Connections per worker**: 800 simultaneous connections
111+
112+
The Docker container automatically uses Gunicorn and is configured with static sync enabled by default.
113+
114+
> **Note**: The application code automatically detects the execution environment. When run with `python3 sparql_oc.py`, it uses the built-in web.py server. When run with Gunicorn (as in Docker), it uses the WSGI interface.
115+
98116
### Dockerfile
99117

100118
You can change these variables in the Dockerfile:
@@ -112,13 +130,11 @@ ENV BASE_URL="sparql.opencitations.net" \
112130
SYNC_ENABLED="true"
113131

114132
# Install system dependencies required for Python package compilation
115-
# We clean up apt cache after installation to reduce image size
116133
RUN apt-get update && \
117134
apt-get install -y \
118135
git \
119136
python3-dev \
120-
build-essential && \
121-
apt-get clean
137+
build-essential
122138

123139
# Set the working directory for our application
124140
WORKDIR /website
@@ -133,6 +149,11 @@ RUN pip install -r requirements.txt
133149
# Expose the port that our service will listen on
134150
EXPOSE 8080
135151

136-
# Start the application
137-
# The Python script will now read environment variables for SPARQL configurations
138-
CMD ["python3", "sparql_oc.py"]
152+
# Start the application with gunicorn for production
153+
CMD ["gunicorn", \
154+
"-w", "2", \
155+
"--worker-class", "gevent", \
156+
"--worker-connections", "800", \
157+
"--timeout", "1200", \
158+
"-b", "0.0.0.0:8080", \
159+
"sparql_oc:application"]

docker_version.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.3.6sync
1+
1.3.8sync-gunitest

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,5 @@ web.py
3939
SPARQLWrapper
4040
gitpython
4141
APScheduler==3.10.1
42+
gunicorn==21.2.0
43+
gevent==23.9.1

sparql_oc.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
# URL Mapping
4646
urls = (
4747
"/", "Main",
48+
"/static/(.*)", "Static",
4849
"/meta", "SparqlMeta",
4950
'/favicon.ico', 'Favicon',
5051
"/index", "SparqlIndex"
@@ -74,6 +75,9 @@
7475
# App Web.py
7576
app = web.application(urls, globals())
7677

78+
# WSGI application
79+
application = app.wsgifunc()
80+
7781
def sync_static_files():
7882
"""
7983
Function to synchronize static files using sync_static.py
@@ -219,6 +223,36 @@ class SparqlMeta(Sparql):
219223
def __init__(self):
220224
Sparql.__init__(self, env_config["sparql_endpoint_meta"],
221225
"meta", "/meta")
226+
227+
class Static:
228+
def GET(self, name):
229+
"""Serve static files"""
230+
static_dir = "static"
231+
file_path = os.path.join(static_dir, name)
232+
233+
if not os.path.exists(file_path):
234+
raise web.notfound()
235+
236+
# Content types
237+
ext = os.path.splitext(name)[1]
238+
content_types = {
239+
'.css': 'text/css',
240+
'.js': 'application/javascript',
241+
'.png': 'image/png',
242+
'.jpg': 'image/jpeg',
243+
'.jpeg': 'image/jpeg',
244+
'.gif': 'image/gif',
245+
'.svg': 'image/svg+xml',
246+
'.ico': 'image/x-icon',
247+
'.woff': 'font/woff',
248+
'.woff2': 'font/woff2',
249+
'.ttf': 'font/ttf',
250+
}
251+
252+
web.header('Content-Type', content_types.get(ext, 'application/octet-stream'))
253+
254+
with open(file_path, 'rb') as f:
255+
return f.read()
222256

223257

224258
# Run the application

0 commit comments

Comments
 (0)