gunicorn

gunicorn

March 24, 2024 | permanent

Server #

tags
Python , Python Apps

Gunicorn ‘Green Unicorn’ is a Python WSGI HTTP Server for UNIX.

  • It’s a pre-fork worker model.
  • The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resources, and fairly speedy.

URL Github

basic configuration #

$ pip install gunicorn
  $ cat myapp.py
    def app(environ, start_response):
        data = b"Hello, World!\n"
        start_response("200 OK", [
            ("Content-Type", "text/plain"),
            ("Content-Length", str(len(data)))
        ])
        return iter([data])

  $ gunicorn -w 4 $ pip install gunicorn
  $ cat myapp.py
    def app(environ, start_response):
        data = b"Hello, World!\n"
        start_response("200 OK", [
            ("Content-Type", "text/plain"),
            ("Content-Length", str(len(data)))
        ])
        return iter([data])
  $ gunicorn -w 4 -b 127.0.0.1:8000  myapp:app
  [2014-09-10 10:22:28 +0000] [30869] [INFO] Listening at: http://127.0.0.1:8000 (30869)
  [2014-09-10 10:22:28 +0000] [30869] [INFO] Using worker: sync
  [2014-09-10 10:22:28 +0000] [30874] [INFO] Booting worker with pid: 30874
  [2014-09-10 10:22:28 +0000] [30875] [INFO] Booting worker with pid: 30875
  [2014-09-10 10:22:28 +0000] [30876] [INFO] Booting worker with pid: 30876
  [2014-09-10 10:22:28 +0000] [30877] [INFO] Booting worker with pid: 30877myapp:app
  [2014-09-10 10:22:28 +0000] [30869] [INFO] Listening at: http://127.0.0.1:8000 (30869)
  [2014-09-10 10:22:28 +0000] [30869] [INFO] Using worker: sync
  [2014-09-10 10:22:28 +0000] [30874] [INFO] Booting worker with pid: 30874
  [2014-09-10 10:22:28 +0000] [30875] [INFO] Booting worker with pid: 30875
  [2014-09-10 10:22:28 +0000] [30876] [INFO] Booting worker with pid: 30876
  [2014-09-10 10:22:28 +0000] [30877] [INFO] Booting worker with pid: 30877

using configuration file #

import os

print("gunicorn.config.py called")
workers = os.environ.get("GUNICORN_WORKERS", 2)
worker_class = "uvicorn.workers.UvicornWorker"
port = os.environ.get("GUNICORN_PORT", 8000)


def post_fork(server, worker):
    print("post_fork called")
    server.log.info("Worker spawned (pid: %s)", worker.pid)
    from invoicing_apis.apm import initialize_tracing
    initialize_tracing()
gunicorn -c gunicorn.config.py invoicing_apis.asgi:application

stackoverflow

Adding OpenTelemetry for the APM #

ref using post_fork in the gunicorn.config.py and tracking there post_form ref 2 opentelemetry with gunicorn and asgi I used these configurations in invoicing-apis project.

import os

import MySQLdb
from opentelemetry import trace
from opentelemetry.exporter.zipkin.json import ZipkinExporter
from opentelemetry.instrumentation.celery import CeleryInstrumentor
from opentelemetry.instrumentation.django import DjangoInstrumentor
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
from opentelemetry.instrumentation.celery import CeleryInstrumentor
from opentelemetry.instrumentation.dbapi import trace_integration
from opentelemetry.instrumentation.django import DjangoInstrumentor
from opentelemetry.instrumentation.mysql import MySQLInstrumentor


APM_ENDPOINT_URL = os.environ.get("APM_ENDPOINT_URL")
APM_PUBLIC_KEY = os.environ.get("APM_PUBLIC_KEY")

apm_upload_endpoint_url = f"https://{APM_ENDPOINT_URL}/20200101/observations/public-span?dataFormat=zipkin&dataFormatVersion=2&dataKey={APM_PUBLIC_KEY}"

print("APM Endpoint URL:")
print(apm_upload_endpoint_url)


zipkin_exporter = ZipkinExporter(
    endpoint=apm_upload_endpoint_url,
    # Add other parameters as necessary
)


# Set up the tracer provider and processor
trace.set_tracer_provider(
    TracerProvider(
        resource=Resource.create(
            {
                "service.name": "invoicing-apis",
                "service.instance.id": "instance-replace-with-env-var",
            }
        )
    )
)
trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(zipkin_exporter))
# DjangoInstrumentor uses DJANGO_SETTINGS_MODULE to instrument the project.
# Make sure the var is available before you call the DjangoInstrumentor.


def initialize_tracing():
    trace_integration(MySQLdb, "connect", "mysql")
    DjangoInstrumentor().instrument()
    CeleryInstrumentor().instrument()
    MySQLInstrumentor().instrument()
    try:
        from opentelemetry.instrumentation.sqlite3 import SQLite3Instrumentor
        print("using sqlite3 tracingg")
    except ImportError:
        print("NOT using sqlite3 tracing")
    else:
        SQLite3Instrumentor().instrument()
    return trace.get_tracer(__name__)

gunicorn.config.py, above.

Commands to start the server #

 venv_dir /bin/gunicorn -c ./server/gunicorn.config.py server.main:app -b 0.0.0.0: app_port  -t 10000 --log-file /var/log/gunicorn/app.log  --error-logfile /var/log/gunicorn/error.log --access-logfile /var/log/gunicorn/access.log --capture-output
Restart=on-failure

log settings

Running as a service #

[Unit] Description= app_name server After=network.target

[Service] User= app_user Group= app_user WorkingDirectory= repo_dir /backend

Environment=“PATH= venv_dir /bin” Environment=“APM_ENDPOINT_URL= APM_ENDPOINT_URL " Environment=“APM_PUBLIC_KEY= APM_PUBLIC_KEY " Environment=“OPENAI_API_KEY= OPENAI_API_KEY " Environment=“COHERE_GENERATIVE_AI_CONFIG_FILE_PATH= COHERE_GENERATIVE_AI_CONFIG_FILE_PATH " Environment=“OPENSEARCH_SEARCH_DOMAIN= OPENSEARCH_SEARCH_DOMAIN " Environment=“PDFS_DIR= pdfs_dir " ExecStart= venv_dir /bin/gunicorn -c ./server/gunicorn.config.py server.main:app -b 0.0.0.0: app_port -t 10000 –log-file /var/log/gunicorn/app.log –error-logfile /var/log/gunicorn/error.log –access-logfile /var/log/gunicorn/access.log –capture-output Restart=on-failure

[Install] WantedBy=multi-user.target


No notes link to this note

Go to random page

Previous Next