diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..edc34614 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# Distribution / packaging +.Python +.venv +env/ +bin/ +build/ +develop-eggs/ +dist/ +eggs/ +lib64/ +parts/ +sdist/ +var/ +.vscode/ +*.egg-info/ +.installed.cfg +*.egg + +# vim +*.swp diff --git a/README.md b/README.md index d8d48477..23af42d1 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,66 @@ -# Celery on Render +# Celery Task Queue with Flower -This repo can be used to deploy the [Celery](https://github.com/celery/celery) distributed task queue on [Render](https://render.com). It also includes deployment instructions for [Flower](https://github.com/mher/flower), a web monitoring frontend for Celery. +A modern Flask + Celery distributed task queue with Flower monitoring dashboard. +## Tech Stack + +- **Flask 3.0** - Web framework +- **Celery 5.3** - Distributed task queue +- **Flower 2.0** - Real-time Celery monitoring +- **Redis** - Message broker & result backend + +## Local Development + +### Prerequisites + +- Python 3.10+ +- Redis server running locally + +### Setup + +```bash +# Create virtual environment +python -m venv venv +source venv/bin/activate # On Windows: venv\Scripts\activate + +# Install dependencies +pip install -r requirements.txt + +# Set environment variables (optional) +export CELERY_BROKER_URL=redis://localhost:6379/0 +export CELERY_RESULT_BACKEND=redis://localhost:6379/0 +export FLASK_SECRET_KEY=your-secret-key +``` + +### Running + +Start each service in a separate terminal: + +```bash +# Terminal 1: Start Redis (if not running as a service) +redis-server + +# Terminal 2: Start Celery worker +celery -A tasks worker --loglevel=info + +# Terminal 3: Start Flower monitoring +celery -A tasks flower --port=5555 + +# Terminal 4: Start Flask app +flask run +``` + +Then visit: +- **Web App**: http://localhost:5000 +- **Flower Dashboard**: http://localhost:5555 ## Deployment -Follow the guide at https://render.com/docs/deploy-celery. \ No newline at end of file +Follow the guide at https://render.com/docs/deploy-celery for production deployment on Render. + +## Features + +- Asynchronous task execution +- Real-time task monitoring via Flower +- Task result tracking with Redis backend +- Modern, responsive UI diff --git a/app.py b/app.py index 3ae0a7b9..25468bd4 100644 --- a/app.py +++ b/app.py @@ -1,20 +1,29 @@ import os -from flask import Flask, flash, render_template, redirect, request + +from flask import Flask, flash, redirect, render_template, request + from tasks import add app = Flask(__name__) -app.secret_key = os.getenv('FLASK_SECRET_KEY', "super-secret") +app.secret_key = os.getenv("FLASK_SECRET_KEY", "super-secret") -@app.route('/') +@app.route("/") def main(): - return render_template('main.html') + return render_template("main.html") -@app.route('/add', methods=['POST']) +@app.route("/add", methods=["POST"]) def add_inputs(): - x = int(request.form['x']) - y = int(request.form['y']) - add.delay(x, y) - flash("Your addition job has been submitted.") - return redirect('/') + try: + x = int(request.form["x"]) + y = int(request.form["y"]) + result = add.delay(x, y) + flash(f"Job submitted! Task ID: {result.id[:8]}...") + except (ValueError, KeyError): + flash("Please enter valid numbers for both X and Y.") + return redirect("/") + + +if __name__ == "__main__": + app.run(debug=True) diff --git a/requirements.txt b/requirements.txt index 37fb85c0..e4e658d9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,6 @@ -celery==4.3.0 -Flask==1.0.2 -flower==0.9.3 -gunicorn==19.9.0 -redis==3.2.1 - -# NOTE: Kombu 4.6.5 results in a build failure. Bumping down to 4.6.4 -# See this github issue: https://github.com/celery/kombu/issues/1063 -kombu==4.6.4 +celery==5.3.6 +Flask==3.0.0 +flower==2.0.1 +gunicorn==21.2.0 +redis==5.0.1 +kombu==5.3.4 diff --git a/tasks.py b/tasks.py index 101a88ac..9bcf73f7 100644 --- a/tasks.py +++ b/tasks.py @@ -1,9 +1,27 @@ import os + from celery import Celery -app = Celery('tasks', broker=os.getenv("CELERY_BROKER_URL")) +# Configure Celery with broker and optional result backend +app = Celery( + "tasks", + broker=os.getenv("CELERY_BROKER_URL", "redis://localhost:6379/0"), + backend=os.getenv("CELERY_RESULT_BACKEND", "redis://localhost:6379/0"), +) + +# Celery configuration +app.conf.update( + task_serializer="json", + accept_content=["json"], + result_serializer="json", + timezone="UTC", + enable_utc=True, + task_track_started=True, + result_expires=3600, +) -@app.task -def add(x, y): +@app.task(bind=True) +def add(self, x, y): + """Add two numbers asynchronously.""" return x + y diff --git a/templates/main.html b/templates/main.html index c0584a3c..bd181042 100644 --- a/templates/main.html +++ b/templates/main.html @@ -34,4 +34,4 @@

Asynchronous addition using Celery!

- \ No newline at end of file +