I am working on a pytho app and below is the flask controller where an endpoint is exposed and triggering another script once received request.
import subprocess
from flask import Flask, request, jsonify
import os
from dotenv import load_dotenv
import requests
import json
from requests.auth import HTTPBasicAuth
load_dotenv()
app = Flask(__name__)
environment = os.environ.get('ENVIRONMENT', 'dev')
valid_client = os.environ.get('VALID_CLIENT')
# Load environment-specific configuration from config file
config_file_name = f'config/config_{environment}.json'
client_id = os.environ.get('CLIENT_ID')
client_secret = os.environ.get('CLIENT_SECRET')
try:
with open(config_file_name, 'r') as config_file:
config = json.load(config_file)
except FileNotFoundError:
print(f"Config file '{config_file_name}' not found. Please make sure the file exists.")
exit(1) # Exit the program with an error code
@app.before_request
def authorize_request():
auth_header = request.headers.get("Authorization")
if auth_header is None or not auth_header.startswith("Bearer "):
return jsonify({"message": "Missing or invalid token"}), 401
# Extract the token
bearer_token = auth_header.split(" ")[1]
auth = HTTPBasicAuth(client_id, client_secret)
headers = {
"Content-Type": "application/json",
"Accept": "application/json"
}
# Construct the request body
data = {
"access_token": bearer_token
}
# Make the POST request with authentication and token in the body
response = requests.post(config['token_validation_url'], auth=auth, headers=headers, json=data)
if response.status_code == 200:
response_data = response.json()
if response_data.get("Status") == "INVALID" or not response_data.get("UserId").endswith(valid_client):
return jsonify({"message": "Token validation failed"}), 401
@app.route('/process-csv', methods=['POST'])
def process_csv():
try:
file = request.files['file']
if file and file.filename.endswith('.csv'):
# Save the uploaded CSV file to a temporary location
csv_file_path = f'/tmp/{file.filename}'
file.save(csv_file_path)
subprocess.Popen(['python3', 'publisher.py', csv_file_path])
return jsonify({'message': 'CSV file uploaded and processing started in the background'})
return jsonify({'message': 'Invalid file format. Please upload a CSV file.'}), 400
except Exception as e:
return jsonify({'message': str(e)}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
App Structure:
As of now to deploy the app I am copying the scripts and installing the dependences on the prod linux server and starting up the controller with python3 controller.py
.
Sometimes I am facing issue related to different environment or python version (as compare to local development environment) and managing it’s dependencies on the prod server and had to resolve them manually.
what is the recommended way to deploy the python app ? shall I containerize this app ? Please suggest.
2
Answers
The way I do it is I get a free google cloud VM:
https://many.pw/hosting
"e2-micro" VM. You get a 30GB hard drive, 1GB ram, and two AMD EPYC 7B12 2250 MHz processors. That’s enough to run a nice little site with plenty of traffic.
And I put the very latest version of Ubuntu 22.04.3 LTS (Jammy Jellyfish) which comes with a nice recent version of python.
Then I just clone the python repo on the server and use systemd to run uvicorn:
There are several ways to run python app on the production server.
First of all, flask used development server by default. For production you can use uWSGI or gunicorn or other wsgi server.
I recomended tiangolo/uwsgi-nginx-flask this docker image, because it’s easy to use with flask apps.