From patchwork Sat Mar 7 21:01:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Fr=C3=A9d=C3=A9ric_Mangano-Tarumi?= X-Patchwork-Id: 1544 Return-Path: Delivered-To: patchwork@archlinux.org Received: from apollo.archlinux.org (localhost [127.0.0.1]) by apollo.archlinux.org (Postfix) with ESMTP id 786B2177D2436 for ; Sat, 7 Mar 2020 21:02:01 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on apollo.archlinux.org X-Spam-Level: X-Spam-Status: No, score=-2.2 required=5.0 tests=DKIM_INVALID=1, DKIM_SIGNED=0.1,MAILING_LIST_MULTI=-1,RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001 autolearn=ham autolearn_force=no version=3.4.4 X-Spam-BL-Results: [127.0.9.2] Received: from orion.archlinux.org (orion.archlinux.org [88.198.91.70]) by apollo.archlinux.org (Postfix) with ESMTPS for ; Sat, 7 Mar 2020 21:02:01 +0000 (UTC) Received: from orion.archlinux.org (localhost [127.0.0.1]) by orion.archlinux.org (Postfix) with ESMTP id 17E4019C8DE8C8; Sat, 7 Mar 2020 21:01:58 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [5.9.250.164]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits)) (No client certificate requested) (Authenticated sender: luna) by orion.archlinux.org (Postfix) with ESMTPSA id ECDE319C8DE8C4; Sat, 7 Mar 2020 21:01:57 +0000 (UTC) Authentication-Results: orion.archlinux.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mg0.fr header.i=@mg0.fr header.b=xvndUneR Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id E29092A8EF; Sat, 7 Mar 2020 21:01:57 +0000 (UTC) Authentication-Results: luna.archlinux.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=mg0.fr header.i=@mg0.fr header.b=xvndUneR Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id 872AF2A8ED for ; Sat, 7 Mar 2020 21:01:54 +0000 (UTC) Received: from orion.archlinux.org (orion.archlinux.org [IPv6:2a01:4f8:160:6087::1]) by luna.archlinux.org (Postfix) with ESMTPS for ; Sat, 7 Mar 2020 21:01:54 +0000 (UTC) Received: from orion.archlinux.org (localhost [127.0.0.1]) by orion.archlinux.org (Postfix) with ESMTP id 0710819C8DE8C0 for ; Sat, 7 Mar 2020 21:01:53 +0000 (UTC) Received: from tsubame.mg0.fr (tsubame.mg0.fr [IPv6:2001:41d0:401:3100::402b]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by orion.archlinux.org (Postfix) with ESMTPS for ; Sat, 7 Mar 2020 21:01:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mg0.fr; s=tsubame; h=Content-Transfer-Encoding:Content-Type:MIME-Version:Message-ID: Subject:To:From:Date:Sender:Reply-To:Cc:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=l8BpQnRp+9hEZYf+tZkwaW5jWWCcBdTYLVvqUldzbc8=; b=xvndUneRMKKV1c7xahW1H0RIGr x6FTdSp6WhO5iGUkGSG+U6vsl63bW+7YeGsrbTnFl3sW3oiK+q0B096cQyAGx9jbqAmQAivZYmlBD Ygkd4qUVGMOqOEnsfSqZmoPlLDgcqEqVjcmAZb5rlhRcHYEzFgH85uAU7ICZDFnIiOsI=; Received: from fmang by tsubame.mg0.fr with local (Exim 4.93) (envelope-from ) id 1jAga0-00AGt9-4r for aur-dev@archlinux.org; Sat, 07 Mar 2020 22:01:52 +0100 Date: Sat, 7 Mar 2020 22:01:52 +0100 From: =?utf-8?b?RnLDqWTDqXJpYw==?= Mangano-Tarumi To: aur-dev@archlinux.org Subject: [PATCH] Proof-of-concept of a =?utf-8?q?dual_PHP=E2=80=93Python?= stack Message-ID: <20200307210152.GA2448188@tsubame.mg0.fr> MIME-Version: 1.0 Content-Disposition: inline X-BeenThere: aur-dev@archlinux.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Arch User Repository \(AUR\) Development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: aur-dev-bounces@archlinux.org Sender: "aur-dev" Here’s a demonstration of a Python web stack running next to the current PHP stack, such that it’s invisible to the client. This approach aims at providing a way to migrate the PHP code base to Python, one endpoint after another, with as little glue as possible to have the two backends collaborate. Since they are both mounted on the web root, Python could implement, say, /packages/ and leave the rest to PHP. As soon as PHP yields it by returning 404 on this URL, Python will take over automatically. To run it, you need python-flask and nginx. Then, you need to start PHP, Flask, and nginx, in whatever order: $ cd path/to/aurweb $ AUR_CONFIG="$PWD/conf/config" php -S 127.0.0.1:8080 -t web/html $ FLASK_APP=aurweb.wsgi flask run $ nginx -p . -c conf/nginx.conf You may then open http://localhost:8081/ and http://localhost:8081/hello to check that the former URL goes to PHP and the latter to Flask. The key concept is nginx’s proxy_next_upstream feature. We set Flask as a fallback backend, and tell nginx to use the fallback only on 404 from PHP. See http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream The main limitation of this approach is that PHP and Python need to use the same gateway protocol, probably FastCGI or HTTP. A minor caveat with this system is that the body of the 404 returned by PHP is lost, though it could contain useful information like “Package X doesn’t exist”, rather than a generic “Page not found”. Luckily, all the 404 cases are handled by 404.php, so we could port its logic to Flask and preserve the current behavior. --- aurweb/wsgi.py | 15 +++++++++++++++ conf/nginx.conf | 23 +++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 aurweb/wsgi.py create mode 100644 conf/nginx.conf diff --git a/aurweb/wsgi.py b/aurweb/wsgi.py new file mode 100644 index 00000000..fd6b67d3 --- /dev/null +++ b/aurweb/wsgi.py @@ -0,0 +1,15 @@ +from flask import Flask, request + + +def create_app(): + app = Flask(__name__) + + @app.route('/hello', methods=['GET', 'POST']) + def hello(): + return ( + f"{request.method} {request.url}\n" + f"{request.headers}" + f"{request.get_data(as_text=True)}\n" + ), {'Content-Type': 'text/plain'} + + return app diff --git a/conf/nginx.conf b/conf/nginx.conf new file mode 100644 index 00000000..8e6e4edb --- /dev/null +++ b/conf/nginx.conf @@ -0,0 +1,23 @@ +events { +} + +daemon off; +error_log /dev/stderr info; +pid nginx.pid; + +http { + access_log /dev/stdout; + + upstream aurweb { + server [::1]:8080 max_fails=0; + server 127.0.0.1:5000 backup max_fails=0; + } + + server { + listen 8081; + location / { + proxy_pass http://aurweb; + proxy_next_upstream http_404 non_idempotent; + } + } +}