-
Notifications
You must be signed in to change notification settings - Fork 0
AP-856: scaffold a basic flask+celery app #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
anarchivist
wants to merge
7
commits into
main
Choose a base branch
from
AP-856
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
1613303
AP-856: scaffold a basic flask+celery app
anarchivist f5d9353
add celery flower and change default queue
anarchivist ee8cc9b
refactor controllers into blueprints
anarchivist 0b12f56
get flask app config from prefixed env variables
anarchivist 383826b
add readme and tighten up compose file
anarchivist b6fc592
add a nice root page with a silly image
anarchivist c78a893
update uid to align with what's in lap/workflow
anarchivist File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| name: Build / Test / Push | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - "**" | ||
| workflow_call: | ||
| workflow_dispatch: | ||
|
|
||
| env: | ||
| BUILD_SUFFIX: -build-${{ github.run_id }}_${{ github.run_attempt }} | ||
|
|
||
| jobs: | ||
| docker-build: | ||
| uses: BerkeleyLibrary/.github/.github/workflows/docker-build.yml@3.1.0 | ||
| with: | ||
| image: ghcr.io/${{ github.repository }} | ||
| secrets: inherit | ||
|
|
||
| test: | ||
| runs-on: ubuntu-24.04 | ||
| needs: docker-build | ||
| env: | ||
| COMPOSE_FILE: docker-compose.yml:docker-compose.ci.yml | ||
| DOCKER_APP_IMAGE: ${{ needs.docker-build.outputs.image }} | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Set up Docker Compose | ||
| uses: docker/setup-compose-action@v2 | ||
|
|
||
| - name: Login to GitHub Container Registry | ||
| uses: docker/login-action@v4 | ||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Basic setup | ||
| run: | | ||
| ARTIFACTS_DIR="${RUNNER_TEMP}/artifacts" | ||
| mkdir -p "$ARTIFACTS_DIR" | ||
| echo "ARTIFACTS_DIR=${ARTIFACTS_DIR}" >> $GITHUB_ENV | ||
| echo "TEST_START=$(date +%s)" >> $GITHUB_ENV | ||
| - name: Setup the stack | ||
| run: | | ||
| docker compose run app bin/dbinit | ||
| docker compose up --wait | ||
| - name: Install testing and linting dependencies | ||
| run: | | ||
| docker compose exec app pip install --no-cache-dir -e .[test,lint] | ||
| - name: Run pytest | ||
| run: | | ||
| docker compose exec app pytest | ||
|
|
||
| - name: Copy out artifacts | ||
| if: ${{ always() }} | ||
| run: | | ||
| docker compose cp app:/app/artifacts "${ARTIFACTS_DIR}" || true | ||
| docker compose logs > "${ARTIFACTS_DIR}/docker-compose-services.log" | ||
| docker compose config > "${ARTIFACTS_DIR}/docker-compose.merged.yml" | ||
| docker events --json --since $TEST_START --until `date +%s` | tee "${ARTIFACTS_DIR}/docker-events.json" | ||
|
|
||
| - name: Upload the test report | ||
| if: ${{ always() }} | ||
| uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: quiabo Build Report (${{ github.run_id }}_${{ github.run_attempt }}) | ||
| path: ${{ env.ARTIFACTS_DIR }} | ||
| if-no-files-found: error | ||
|
|
||
| push: | ||
| needs: | ||
| - docker-build | ||
| - test | ||
| uses: BerkeleyLibrary/.github/.github/workflows/docker-push.yml@3.1.0 | ||
| with: | ||
| image: ghcr.io/${{ github.repository }} | ||
| build-image-arm64: ${{ needs.docker-build.outputs.image-arm64 }} | ||
| build-image-x64: ${{ needs.docker-build.outputs.image-x64 }} | ||
| secrets: inherit |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| name: Release | ||
|
|
||
| on: | ||
| push: | ||
| tags: | ||
| - '**' | ||
| workflow_dispatch: | ||
|
|
||
| jobs: | ||
| release: | ||
| uses: BerkeleyLibrary/.github/.github/workflows/docker-release.yml@main | ||
| with: | ||
| image: ghcr.io/${{ github.repository }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -216,3 +216,7 @@ __marimo__/ | |
|
|
||
| # Streamlit | ||
| .streamlit/secrets.toml | ||
|
|
||
| # other stuff | ||
| artifacts/* | ||
| uv.lock | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| FROM python:3.14-slim AS reqs | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want Python version to be an
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we haven't yet done that for other python apps but i'm not opposed. |
||
|
|
||
| ENV APP_USER=quiabo | ||
| ENV APP_UID=40098 | ||
| ENV VIRTUAL_ENV=/venv | ||
|
|
||
| RUN apt-get update -y && apt-get upgrade -y \ | ||
| && apt-get install -y --no-install-recommends \ | ||
| gcc \ | ||
| libpq-dev \ | ||
| libxml2-dev \ | ||
| python3-dev \ | ||
| postgresql-client \ | ||
| && rm -rf /var/lib/apt/lists/ | ||
|
|
||
| RUN groupadd --system --gid $APP_UID $APP_USER \ | ||
| && useradd --home-dir /app --system --uid $APP_UID --gid $APP_USER $APP_USER | ||
|
|
||
| RUN mkdir -p /app && mkdir -p /venv | ||
|
|
||
| RUN chown -R $APP_USER:$APP_USER /app /venv | ||
|
|
||
| USER $APP_USER | ||
|
|
||
| RUN python -m venv /venv | ||
| ENV PATH=/venv/bin:$PATH | ||
|
|
||
| RUN python -m pip install -U setuptools | ||
|
|
||
| WORKDIR /app | ||
|
|
||
| COPY pyproject.toml . | ||
|
|
||
| FROM reqs AS app | ||
|
|
||
| WORKDIR /app | ||
| USER $APP_USER | ||
|
|
||
| COPY quiabo quiabo | ||
| COPY bin bin | ||
| COPY README.md README.md | ||
| COPY test test | ||
| RUN pip install --no-cache-dir -e . | ||
|
|
||
| EXPOSE 8000 | ||
|
|
||
| CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0", "quiabo:app"] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,59 @@ | ||
| # quiabo | ||
| Backend web service for running OCR processes | ||
| #  quiabo | ||
|
|
||
| `quiabo` is a backend web service for running OCR jobs implemented as a Flask and Celery application. | ||
|
|
||
| ## Dependencies | ||
|
|
||
| Python dependencies are declared in `pyproject.toml`. | ||
|
|
||
| ## Development | ||
|
|
||
| Spin up the application using Docker Compose. There are number of dependencies (Postgres and Redis) as well as Flask/Celery app components (`app`, `worker`, and optionially `flower`). Redis serves as the Celery broker (source of jobs) and Postgres is the Celery results backend. | ||
|
|
||
| ```bash | ||
| # Build the Docker image for app, worker, and flower | ||
| docker compose build | ||
|
|
||
| # Create the postgres database; only needed the first time | ||
| docker compose run --rm app bin/dbinit | ||
|
|
||
| # Start the Flask app, which will be running on http://localhost:8000/ | ||
| docker compose up --detach | ||
|
|
||
| # Optionally start Flower, which is a dashboard for the Celery queue and | ||
| # will be running on http://localhost:5555/ | ||
| docker compose up --profile flower --detach | ||
| ``` | ||
|
|
||
| ## Testing | ||
|
|
||
| Once the stack is started, execute the tests by running `pytest` in one | ||
| of the running containers. Note that testing and linting dependencies are | ||
| not installed by default, so you'll need to do that too. | ||
|
|
||
| ```bash | ||
| # Install the testing and linting dependencies | ||
|
|
||
| docker compose exec app pip install --no-cache-dir -e .[test,lint] | ||
|
|
||
| # Run all the tests | ||
| docker compose exec app pytest | ||
|
|
||
| # Run tests with a specific marker | ||
| # Example: only run the unit tests | ||
| docker compose exec app pytest -m unit | ||
| ``` | ||
|
|
||
| Test results/reports are written to `./artifacts/pytest`. | ||
|
|
||
| ## Configuration | ||
|
|
||
| `quiabo`'s configuration is handled by environment variables using Flask's | ||
| [`from_prefixed_env()`](https://flask.palletsprojects.com/en/stable/config/#configuring-from-environment-variables) method, using `QUIABO` as the | ||
| prefix. Celery configuration is set using the same method. At a minimum, | ||
| you will need to set the following: | ||
|
|
||
| | Environment variable | Purpose | Example | | ||
| | -------------------- | ------- | ------- | | ||
| | `QUIABO_CELERY__broker_url` | Connection URL for the Celery broker (e.g. Redis) | `redis://redis:6379` | | ||
| | `QUIABO_CELERY__result_backend` | SQLAlchemy connection URL for the Celery result backend (e.g. Postgres) | `db+postgresql://postgres:postgres@db:5432/quiabo` | |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| #!/bin/sh -e | ||
|
|
||
| # Initialise the configured database environment for use with quiabo | ||
| # | ||
| # Copyright © 2026 The Regents of the University of California. MIT license. | ||
|
|
||
| # Use the credentials from the app's environment. | ||
| export PGHOST=${POSTGRES_HOST:-db} | ||
| export PGPORT=${POSTGRES_PORT:-5432} | ||
| export PGUSER=${POSTGRES_USER} | ||
| export PGPASSWORD=${POSTGRES_PASSWORD} | ||
| export PGDATABASE=${POSTGRES_DB} | ||
|
|
||
| # Determine if the database needs to be created or not. | ||
| if [ "$(psql -d template1 -t -A -c "SELECT COUNT(*) FROM pg_database WHERE datname='${POSTGRES_DB}';")" = '0' ]; then | ||
| echo Creating database ${POSTGRES_DB}... | ||
| createdb | ||
| else | ||
| echo Database ${POSTGRES_DB} already exists. Bye bye! | ||
| fi | ||
|
awilfox marked this conversation as resolved.
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| services: | ||
| db: | ||
| volumes: !reset | ||
|
|
||
| redis: | ||
| volumes: !reset | ||
|
|
||
| app: | ||
| build: !reset | ||
| depends_on: !reset | ||
| ports: !reset | ||
| image: ${DOCKER_APP_IMAGE} | ||
| env_file: !override env.example | ||
| volumes: !reset | ||
|
|
||
| worker: | ||
| build: !reset | ||
| image: ${DOCKER_APP_IMAGE} | ||
| depends_on: !reset | ||
| ports: !reset | ||
| env_file: !override env.example | ||
| volumes: !reset |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| x-dbconfig: | ||
| environment: &dbconfig | ||
| POSTGRES_USER: ${POSTGRES_USER:-quiabo} | ||
| POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-quiabo} | ||
| POSTGRES_HOST: ${POSTGRES_HOST:-db} | ||
| POSTGRES_PORT: ${POSTGRES_PORT:-5432} | ||
| POSTGRES_DB: ${POSTGRES_DB:-quiabo} | ||
|
|
||
| x-quiabo-common: | ||
| environment: &quiabo-common-environment | ||
| QUIABO_CELERY__broker_url: ${QUIABO__CELERY__broker_url:-redis://redis:6379} | ||
| QUIABO_CELERY__result_backend: ${QUIABO__CELERY__result_backend:-db+postgresql://${POSTGRES_USER:-quiabo}:${POSTGRES_PASSWORD:-quiabo}@${POSTGRES_HOST:-db}:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-quiabo}} | ||
| QUIABO_CELERY__task_default_queue: ${QUIABO_CELERY__task_default_queue:-quiabo} | ||
| QUIABO_CELERY__task_ignore_result: ${QUIABO_CELERY__task_ignore_result:-false} | ||
|
|
||
|
|
||
| services: | ||
| db: | ||
| environment: | ||
| <<: *dbconfig | ||
| image: postgres:16 | ||
| healthcheck: | ||
| test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER}"] | ||
| interval: 10s | ||
| retries: 5 | ||
| start_period: 5s | ||
| ports: | ||
| - 5432:5432 | ||
| restart: always | ||
| volumes: | ||
| - postgres-db-volume:/var/lib/postgresql/data | ||
|
|
||
| app: | ||
| build: | ||
| context: . | ||
| depends_on: | ||
| db: | ||
| condition: service_healthy | ||
| redis: | ||
| condition: service_healthy | ||
| environment: | ||
| <<: | ||
| - *quiabo-common-environment | ||
| - *dbconfig | ||
| init: true | ||
| restart: always | ||
| ports: | ||
| - 8000:8000 | ||
| volumes: | ||
| - ./quiabo:/app/quiabo:rw | ||
|
|
||
| worker: | ||
| build: | ||
| context: . | ||
| depends_on: | ||
| db: | ||
| condition: service_healthy | ||
| redis: | ||
| condition: service_healthy | ||
| environment: | ||
| <<: | ||
| - *quiabo-common-environment | ||
| - *dbconfig | ||
| init: true | ||
| restart: always | ||
| command: celery -A quiabo.celery_app worker --loglevel INFO | ||
| volumes: | ||
| - ./quiabo:/app/quiabo:rw | ||
|
|
||
| flower: | ||
| build: | ||
| context: . | ||
| profiles: | ||
| - flower | ||
| depends_on: | ||
| redis: | ||
| condition: service_healthy | ||
| environment: | ||
| <<: *quiabo-common-environment | ||
| init: true | ||
| restart: always | ||
| command: celery -A quiabo.celery_app flower | ||
| healthcheck: | ||
| test: ["CMD", "curl", "--fail", "http://localhost:5555/"] | ||
| interval: 30s | ||
| timeout: 10s | ||
| retries: 5 | ||
| start_period: 30s | ||
| ports: | ||
| - 127.0.0.1:5555:5555 | ||
| volumes: | ||
| - ./quiabo:/app/quiabo:rw | ||
|
|
||
| redis: | ||
| healthcheck: | ||
| test: ["CMD", "redis-cli", "ping"] | ||
| interval: 10s | ||
| timeout: 30s | ||
| retries: 50 | ||
| start_period: 30s | ||
| image: redis:8 | ||
| ports: | ||
| - 6379:6379 | ||
| restart: always | ||
|
|
||
| volumes: | ||
| postgres-db-volume: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| POSTGRES_USER=root | ||
| POSTGRES_PASSWORD=root | ||
| POSTGRES_DB=quiabo |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing terminating newline.