Skip to content

Flask + Redis Counter

A page visit counter built with Flask and Redis. Every page load increments a counter stored in the managed Redis cache. This example demonstrates how AppMecca handles cache provisioning -- a single cache: enabled: true line injects Redis connection details into your containers.

Source: git@gitlab.com:appmecca-sample-apps/flask-redis-counter.git

What This App Demonstrates

  • Managed Redis cache -- cache: enabled: true auto-provisions Redis connection details
  • Stateless app with external state -- the Flask process holds no state; all state lives in Redis
  • Injected environment variables -- REDIS_URL and CELERY_BROKER_URL are set automatically

appmecca.yaml

containers:
  - name: web
    dockerfile: Dockerfile
    context: .

deploy:
  - name: web
    container: web
    port: 5000
    health_check:
      path: /health

redis:
  enabled: true

When cache: enabled: true, AppMecca injects these environment variables into every container:

Variable Example Value Description
REDIS_URL redis://<cache-host>:6379/0 Redis connection URL
CELERY_BROKER_URL (same as REDIS_URL) Convenience alias for Celery
CACHE_PREFIX <app>:<branch>: Key namespace for this app + branch

REDIS_URL and CELERY_BROKER_URL contain the same URL. CELERY_BROKER_URL is provided because Celery looks for it by default, even if your app does not use Celery.

Shared cache, namespaced keys

The managed Redis cache is shared across all apps in the same environment. AppMecca injects CACHE_PREFIX (built from the app's canonical name and branch) so keys stay isolated between apps and between branches. Use this prefix in your application code to prevent key collisions — read it from the environment rather than hardcoding it, because the canonical app name includes your group.

Application Code

app.py

import os
from flask import Flask, jsonify
import redis

app = Flask(__name__)

# Connect to Redis using the APPMECCA-injected URL
r = redis.from_url(os.environ.get("REDIS_URL", "redis://localhost:6379/0"))
PREFIX = os.environ.get("CACHE_PREFIX", "")

@app.route("/")
def index():
    count = r.incr(f"{PREFIX}visits")
    return f"This page has been visited {count} times."

@app.route("/health")
def health():
    return jsonify({"status": "healthy"})

The app reads REDIS_URL to connect to Redis and uses CACHE_PREFIX to namespace its keys. This means:

  • Multiple apps sharing the same cache will not interfere with each other
  • Branch deployments get their own prefix, so a feature/dark-mode deploy cannot read or clobber main's counters

Dockerfile

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]

No entrypoint script is needed here -- there is no database to wait for and no migrations to run. Redis is immediately available when the container starts.

Deploy It

# Register the app
mecca register git@gitlab.com:appmecca-sample-apps/flask-redis-counter.git -e dev

# Build the Docker image
mecca build trigger -e dev -g git@gitlab.com:appmecca-sample-apps/flask-redis-counter.git

# Deploy
mecca app deploy -e dev flask-redis-counter

Your app is live at https://flask-redis-counter-web.dev.appmecca.net. The service name (web) is always part of the hostname, even though this app has only one service — run mecca app show flask-redis-counter -e dev to see the exact URL for your group.

Verify

# Visit the counter
curl https://flask-redis-counter-web.dev.appmecca.net/
# "This page has been visited 1 times."

curl https://flask-redis-counter-web.dev.appmecca.net/
# "This page has been visited 2 times."

# Health check
curl https://flask-redis-counter-web.dev.appmecca.net/health
# {"status": "healthy"}

Database + Cache Together

Many applications need both PostgreSQL and Redis. You can enable both:

database:
  enabled: true

redis:
  enabled: true

When both are enabled, every container receives:

Variable Source
DATABASE_URL Database (the canonical connection string — prefer this)
DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD Database (the same details, split out)
REDIS_URL Cache
CELERY_BROKER_URL Cache
CACHE_PREFIX Cache

See the Django Celery Tasks example for an app that uses both.

Key Takeaways

  • Add cache: enabled: true to your appmecca.yaml -- AppMecca injects REDIS_URL automatically
  • Use CACHE_PREFIX to namespace your Redis keys and avoid collisions with other apps
  • No entrypoint script is needed for cache-only apps -- Redis is always available
  • The cache is shared across all apps in an environment, which is exactly why the prefix matters
  • Note this is the top-level cache: block (the managed Redis cache). The per-service deploy[].cache: block is a different feature — it configures the AppMecca edge cache in front of a service

What's Next?