From 279c541e4d495039587892f66d4cf83ca16cfdf9 Mon Sep 17 00:00:00 2001 From: Caleb Syring Date: Fri, 23 Jan 2026 11:43:01 -0500 Subject: [PATCH] Fix QA env --- Dockerfile | 56 ++++++++++++++++++------------------------ mu-qa.toml | 11 +++++++-- src/critic/app.py | 17 ------------- src/critic/libs/ddb.py | 4 +++ src/lambda_handler.py | 23 +++++++++++++++++ 5 files changed, 60 insertions(+), 51 deletions(-) create mode 100644 src/lambda_handler.py diff --git a/Dockerfile b/Dockerfile index 52b76a8..e873411 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,39 +1,31 @@ -# https://docs.astral.sh/uv/guides/integration/aws-lambda/#deploying-a-docker-image -FROM ghcr.io/astral-sh/uv:0.8.17 AS uv +from public.ecr.aws/lambda/python:3.13 as app -# First, bundle the dependencies into the task root. -FROM public.ecr.aws/lambda/python:3.13 AS builder +# OS +env UV_COMPILE_BYTECODE=1 +env UV_LINK_MODE=copy +## Configure for system level install +env UV_PROJECT_ENVIRONMENT=/var/lang/ -# Enable bytecode compilation, to improve cold-start performance. -ENV UV_COMPILE_BYTECODE=1 +## uv install +copy --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/ -# Disable installer metadata, to create a deterministic layer. -ENV UV_NO_INSTALLER_METADATA=1 +# App +workdir /app -# Enable copy mode to support bind mount caching. -ENV UV_LINK_MODE=copy +## Build / deps +copy pyproject.toml hatch.toml readme.md uv.lock . +copy src/critic/version.py src/critic/version.py +run --mount=type=cache,target=/root/.cache/uv \ + uv sync --frozen --no-dev --inexact -# Bundle the dependencies into the Lambda task root via `uv pip install --target`. -# -# Omit any local packages (`--no-emit-workspace`) and development dependencies (`--no-dev`). -# This ensures that the Docker layer cache is only invalidated when the `pyproject.toml` or `uv.lock` -# files change, but remains robust to changes in the application code. -RUN --mount=from=uv,source=/uv,target=/bin/uv \ - --mount=type=cache,target=/root/.cache/uv \ - --mount=type=bind,source=uv.lock,target=uv.lock \ - --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ - uv export --frozen --no-emit-workspace --no-dev --no-editable -o requirements.txt && \ - uv pip install -r requirements.txt --target "${LAMBDA_TASK_ROOT}" +## Source files after the build for better caching/speed when deps haven't changed +copy src/critic src/critic +copy src/lambda_handler.py src -FROM public.ecr.aws/lambda/python:3.13 +## App Env +env FLASK_DEBUG=0 -# Copy the runtime dependencies from the builder stage. -COPY --from=builder ${LAMBDA_TASK_ROOT} ${LAMBDA_TASK_ROOT} - -# Now everything to do with the app -COPY src/critic/ ${LAMBDA_TASK_ROOT}/ - -# Uncomment this to get the CMD to be updated in the image. -# RUN echo 'd' > /tmp/annoying.txt - -CMD ["app.lambda_handler"] +# Lambda Entry Point +# The lamba runtime environment will use this dotted path as the entry point to our app when +# the lambda function is invoked. It must be a function, it doesn't handle class methods. +cmd ["lambda_handler.entry"] diff --git a/mu-qa.toml b/mu-qa.toml index a63e93d..8688948 100644 --- a/mu-qa.toml +++ b/mu-qa.toml @@ -1,6 +1,13 @@ project-org = 'Level 12' image-name = 'critic' -[tool.mu.event-rules.run-due-checks] +policy-arns = [ + 'arn:aws:iam::089600762287:policy/CriticDDBAccessQA' +] + +[deployed-env] +CRITIC_NAMESPACE = 'qa' + +[event-rules.run-due-checks] action='run_due_checks' -cron = '* * * * *' # Every minute on the minute +cron = '* * * * ? *' # Every minute on the minute diff --git a/src/critic/app.py b/src/critic/app.py index a1ee2ad..0577c94 100644 --- a/src/critic/app.py +++ b/src/critic/app.py @@ -1,9 +1,6 @@ import logging from flask import Flask -import mu - -from critic.tasks import run_due_checks log = logging.getLogger() @@ -29,17 +26,3 @@ def logs_example(): @app.route('/error') def error(): raise RuntimeError('Deliberate runtime error') - - -class ActionHandler(mu.ActionHandler): - wsgi_app = app - - @staticmethod - def run_due_checks(event, context): - """Triggered by EventBridge rule, invokes `run_due_checks` task.""" - log.info('Invoking run_due_checks') - run_due_checks.invoke() - - -# The entry point for AWS lambda has to be a function -lambda_handler = ActionHandler.on_event diff --git a/src/critic/libs/ddb.py b/src/critic/libs/ddb.py index f076184..85ff35b 100644 --- a/src/critic/libs/ddb.py +++ b/src/critic/libs/ddb.py @@ -91,6 +91,10 @@ def namespace(table_name: str) -> str: @classmethod def name(cls) -> str: + namespace = os.environ.get('CRITIC_NAMESPACE', '') + if namespace in ('prod', 'qa'): + # Prod and QA envs don't have namespaced tables + return cls.base_name return cls.namespace(cls.base_name) @classmethod diff --git a/src/lambda_handler.py b/src/lambda_handler.py new file mode 100644 index 0000000..09fc209 --- /dev/null +++ b/src/lambda_handler.py @@ -0,0 +1,23 @@ +import logging + +import mu + +from critic.app import app +from critic.tasks import run_due_checks + + +log = logging.getLogger() + + +class ActionHandler(mu.ActionHandler): + wsgi_app = app + + @staticmethod + def run_due_checks(event, context): + """Triggered by EventBridge rule, invokes `run_due_checks` task.""" + log.info('Invoking run_due_checks') + run_due_checks.invoke() + + +# The entry point for AWS lambda has to be a function +entry = ActionHandler.on_event