From d14c6a1941c0e0f1a6abd38dc6c3c2b0ea0b51b9 Mon Sep 17 00:00:00 2001 From: Christian Fosli Date: Thu, 13 Jul 2023 12:59:57 +0200 Subject: [PATCH] [wip] feat: Add highscore cleanup job Adds cleanup job for no-longer-needed highscores in rust. Similar to the one in fsharp that was removed in 03f5eb69b2efa7e8ae9805262f631bd353e8af70 --- .github/workflows/highscore_api.yaml | 20 +++- .github/workflows/highscore_cleanup_job.yaml | 92 +++++++++++++++++++ .github/workflows/wasm_app.yml | 47 +++++++--- Cargo.lock | 54 +++++++---- Cargo.toml | 3 +- README.md | 5 +- docker-compose.override.yml | 14 +++ docker-compose.yml | 21 ++++- front-end/Dockerfile | 2 + highscore-api/Dockerfile | 2 + highscore-cleanup-job/Cargo.toml | 19 ++++ highscore-cleanup-job/Dockerfile | 34 +++++++ highscore-cleanup-job/src/main.rs | 97 ++++++++++++++++++++ highscore-types/src/lib.rs | 4 + terraform/api.tf | 7 -- terraform/cleanup-job.tf | 20 ++++ terraform/containerapp-env.tf | 7 ++ 17 files changed, 397 insertions(+), 51 deletions(-) create mode 100644 .github/workflows/highscore_cleanup_job.yaml create mode 100644 docker-compose.override.yml create mode 100644 highscore-cleanup-job/Cargo.toml create mode 100644 highscore-cleanup-job/Dockerfile create mode 100644 highscore-cleanup-job/src/main.rs create mode 100644 terraform/cleanup-job.tf create mode 100644 terraform/containerapp-env.tf diff --git a/.github/workflows/highscore_api.yaml b/.github/workflows/highscore_api.yaml index 38101c8..706a159 100644 --- a/.github/workflows/highscore_api.yaml +++ b/.github/workflows/highscore_api.yaml @@ -26,15 +26,25 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Build with docker + - name: Prepare docker compose file(s) run: | - tags="-t ghcr.io/christianfosli/snake/highscore-api:$(git rev-parse --short HEAD)" + printf 'Deleting docker-compose.override.yml (it is only used during development)\n' + rm docker-compose.override.yml + + printf "Adding commit sha as build tag\n" + COMMIT_SHA="$(git rev-parse --short HEAD)" yq -i \ + '.services.api.build.tags[0] = strenv(COMMIT_SHA)' docker-compose.yml + if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - printf 'Banch is main! Tagging with latest\n' - tags="$tags -t ghcr.io/christianfosli/snake/highscore-api:latest" + printf 'Banch is main! Adding latest as build tag\n' + yq -i '.services.api.build.tags[1] = "latest"' docker-compose.yml fi - docker build -f highscore-api/Dockerfile $tags . + printf '\n\n' + yq '.services.api' docker-compose.yml + + - name: Build with docker compose + run: docker compose build api env: DOCKER_BUILDKIT: 1 diff --git a/.github/workflows/highscore_cleanup_job.yaml b/.github/workflows/highscore_cleanup_job.yaml new file mode 100644 index 0000000..0b4f5d7 --- /dev/null +++ b/.github/workflows/highscore_cleanup_job.yaml @@ -0,0 +1,92 @@ +name: highscore_cleanup_job + +on: + push: + branches: [main] + paths: + - highscore-cleanup-job/** + - .github/workflows/highscore_cleanup_job.yaml + pull_request: + branches: [main] + paths: + - highscore-cleanup-job/** + - .github/workflows/highscore_cleanup_job.yaml + +permissions: + # required for federated credentials to access azure + id-token: write + # required for federated credentials to access azure + contents: read + # required to push to ghcr + packages: write + +jobs: + build: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - name: Prepare docker compose file(s) + run: | + printf 'Deleting docker-compose.override.yml (it is only used during development)\n' + rm docker-compose.override.yml + + printf "Adding commit sha as build tag\n" + COMMIT_SHA="$(git rev-parse --short HEAD)" yq -i \ + '.services.cleanup-job.build.tags[0] = strenv(COMMIT_SHA)' docker-compose.yml + + if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then + printf 'Banch is main! Adding latest as build tag\n' + yq -i '.services.cleanup-job.build.tags[1] = "latest"' docker-compose.yml + fi + + printf '\n\n' + yq '.services.cleanup-job' docker-compose.yml + + - name: Build with docker compose + run: docker compose build api + env: + DOCKER_BUILDKIT: 1 + + - name: Login to ghcr + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Push + run: docker push --all-tags ghcr.io/christianfosli/snake/highscore-cleanup-job + + deploy_staging: + needs: build + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - uses: azure/login@v1 + with: + client-id: ${{ secrets.ARM_CLIENT_ID }} + subscription-id: ${{ secrets.ARM_SUBSCRIPTION_ID }} + tenant-id: ${{ secrets.ARM_TENANT_ID }} + + - run: | + az containerapp update -n caj-snakehighscorecleanup-staging -g rg-snake-staging \ + --image "ghcr.io/christianfosli/snake/highscore-cleanup-job:$(git rev-parse --short $HEAD)" + + deploy_prod: + if: github.event_name != 'pull_request' + needs: deploy_staging + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - uses: azure/login@v1 + with: + client-id: ${{ secrets.ARM_CLIENT_ID }} + subscription-id: ${{ secrets.ARM_SUBSCRIPTION_ID }} + tenant-id: ${{ secrets.ARM_TENANT_ID }} + + - run: | + az containerapp update -n caj-snakehighscorecleanup-prod -g rg-snake-prod \ + --image "ghcr.io/christianfosli/snake/highscore-cleanup-job:$(git rev-parse --short $HEAD)" diff --git a/.github/workflows/wasm_app.yml b/.github/workflows/wasm_app.yml index 4dc813d..0620cd8 100644 --- a/.github/workflows/wasm_app.yml +++ b/.github/workflows/wasm_app.yml @@ -37,27 +37,48 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set variables for staging + - name: Prepare docker compose file(s) - PR if: github.event_name == 'pull_request' run: | - echo "BUILD_VERSION=pr_build_$(git rev-parse --short HEAD)" >> $GITHUB_ENV - echo "HIGHSCORE_API_BASE_URL=https://highscores-staging.playsnake.no" >> $GITHUB_ENV + printf 'Deleting docker-compose.override.yml (it is only used for development)\n' + rm docker-compose.override.yml - - name: Set variables for prod + printf 'Adding build args and tags docker-compose.yml\n' + COMMIT_SHA="$(git rev-parse --short HEAD)" \ + HIGHSCORE_API_BASE_URL=https://highscores-staging.playsnake.no \ + yq -i ' + .services.app.build.tags[0] = strenv(COMMIT_SHA) | + .services.app.build.args.VERSION = strenv(COMMIT_SHA) | + .services.app.build.args.HIGHSCORE_API_BASE_URL= strenv(HIGHSCORE_API_BASE_URL) + ' docker-compose.yml + + printf '\n\n' + yq '.services.app' docker-compose.yml + + - name: Prepare docker compose file(s) - Prod if: github.event_name != 'pull_request' run: | + printf 'Deleting docker-compose.override.yml (it is only used for development)\n' + rm docker-compose.override.yml + + printf 'Adding build args and tags to docker-compose.yml\n' + COMMIT_SHA="$(git rev-parse --short HEAD)" \ + HIGHSCORE_API_BASE_URL=https://highscores.playsnake.no \ + yq -i ' + .services.app.build.tags[0] = strenv(COMMIT_SHA) | + .serviecs.app.build.tags[1] = "latest" | + .services.app.build.args.VERSION = strenv(COMMIT_SHA) | + .services.app.build.args.HIGHSCORE_API_BASE_URL= strenv(HIGHSCORE_API_BASE_URL) + ' docker-compose.yml + + printf '\n\n' + yq '.services.app' docker-compose.yml + echo "BUILD_VERSION=$(git rev-parse --short HEAD)" >> $GITHUB_ENV echo "HIGHSCORE_API_BASE_URL=https://highscores.playsnake.no" >> $GITHUB_ENV - name: Docker build - run: | - docker build \ - --build-arg VERSION=$BUILD_VERSION \ - --build-arg HIGHSCORE_API_BASE_URL=$HIGHSCORE_API_BASE_URL \ - -f front-end/Dockerfile \ - -t ghcr.io/christianfosli/snake/wasm-app:$BUILD_VERSION \ - -t ghcr.io/christianfosli/snake/wasm-app:latest \ - . + run: docker compose build - name: Login to ghcr if: github.event_name != 'pull_request' @@ -76,7 +97,7 @@ jobs: - name: Extract files to deploy # Since we deploy to azure static web app rather than container we need to extract the build files to deploy run: | - container="$(docker create ghcr.io/christianfosli/snake/wasm-app:latest)" + container="$(docker create ghcr.io/christianfosli/snake/wasm-app:$(git rev-parse --short HEAD))" docker cp "$container:/usr/share/nginx/html" out - name: Deploy diff --git a/Cargo.lock b/Cargo.lock index 9578af9..25d8b2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -386,12 +386,12 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.4.0" +version = "5.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +checksum = "6943ae99c34386c84a470c499d3414f66502a41340aa895406e0d2e4a207b91d" dependencies = [ "cfg-if", - "hashbrown 0.12.3", + "hashbrown 0.14.0", "lock_api", "once_cell", "parking_lot_core", @@ -467,9 +467,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" @@ -747,6 +747,24 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "highscore-cleanup-job" +version = "0.1.0" +dependencies = [ + "bson", + "futures", + "highscore-types", + "init-tracing-opentelemetry", + "mongodb", + "opentelemetry", + "serde", + "time", + "tokio", + "tracing", + "tracing-opentelemetry", + "tracing-subscriber", +] + [[package]] name = "highscore-types" version = "0.1.0" @@ -1572,8 +1590,8 @@ checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.2", - "regex-syntax 0.7.3", + "regex-automata 0.3.3", + "regex-syntax 0.7.4", ] [[package]] @@ -1587,13 +1605,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83d3daa6976cffb758ec878f108ba0e062a45b2d6ca3a2cca965338855476caf" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.3", + "regex-syntax 0.7.4", ] [[package]] @@ -1604,9 +1622,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab07dc67230e4a4718e70fd5c20055a4334b121f1f9db8fe63ef39ce9b8c846" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "reqwest" @@ -1828,9 +1846,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.170" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56657f512baabca8f840542f9ca8152aecf182c473c26e46e58d6aab4f6e439" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] @@ -1846,9 +1864,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.170" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77d477848e6b23adba0db397777d5aad864555bc17fd9c89abb3b8009788b7b8" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", @@ -1857,9 +1875,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.100" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1e14e89be7aa4c4b78bdbdc9eb5bf8517829a600ae8eaa39a6e1d960b5185c" +checksum = "b5062a995d481b2308b6064e9af76011f2921c35f97b0468811ed9f6cd91dfed" dependencies = [ "indexmap 2.0.0", "itoa", diff --git a/Cargo.toml b/Cargo.toml index 1b54cac..479809b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,5 +3,6 @@ members = [ "front-end", "highscore-api", - "highscore-types" + "highscore-types", + "highscore-cleanup-job" ] \ No newline at end of file diff --git a/README.md b/README.md index 2336a1e..97a3931 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,9 @@ Snake with optional vim navigation. Visit [playsnake.no](https://www.playsnake.no) to play! -![wasm\_app](https://github.com/christianfosli/visnake-wasm/workflows/wasm_app/badge.svg) -![highscore\_api](https://github.com/christianfosli/visnake-wasm/workflows/highscore_api/badge.svg) +![wasm\_app](https://github.com/christianfosli/snake/workflows/wasm_app/badge.svg) +![highscore\_api](https://github.com/christianfosli/snake/workflows/highscore_api/badge.svg) +![highscore\_cleanup\_job](https://github.com/christianfosli/snake/workflows/highscore_cleanup_job/badge.svg) ![terraform](https://github.com/christianfosli/snake/actions/workflows/terraform.yml/badge.svg) ## Architecture 🏗 diff --git a/docker-compose.override.yml b/docker-compose.override.yml new file mode 100644 index 0000000..90c0f20 --- /dev/null +++ b/docker-compose.override.yml @@ -0,0 +1,14 @@ +services: + app: + build: + args: + BUILD_PROFILE: dev + api: + build: + args: + CARGO_INSTALL_OPTIONS: --debug + cleanup-job: + build: + args: + CARGO_INSTALL_OPTIONS: --debug + diff --git a/docker-compose.yml b/docker-compose.yml index 321096b..83d7fc9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,8 +5,7 @@ services: build: context: . dockerfile: front-end/Dockerfile - args: - BUILD_PROFILE: dev + image: ghcr.io/christianfosli/snake/wasm-app environment: API_URL: http://api:3000 ports: @@ -17,14 +16,24 @@ services: build: context: . dockerfile: highscore-api/Dockerfile - args: - CARGO_INSTALL_OPTIONS: --debug + image: ghcr.io/christianfosli/snake/highscore-api environment: DB_CONNSTR: mongodb://root:secret@db ports: - '3000:3000' depends_on: - - db + db: + condition: service_healthy + cleanup-job: + build: + context: . + dockerfile: highscore-cleanup-job/Dockerfile + image: ghcr.io/christianfosli/snake/highscore-cleanup-job + environment: + DB_CONNSTR: mongodb://root:secret@db + depends_on: + db: + condition: service_healthy db: image: mongo environment: @@ -34,6 +43,8 @@ services: - '27017' volumes: - snake-db:/data/db + healthcheck: + test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet volumes: snake-db: diff --git a/front-end/Dockerfile b/front-end/Dockerfile index 443e482..eafc5b6 100644 --- a/front-end/Dockerfile +++ b/front-end/Dockerfile @@ -16,6 +16,8 @@ RUN --mount=type=bind,source=Cargo.toml,target=Cargo.toml \ --mount=type=bind,source=front-end/Cargo.toml,target=front-end/Cargo.toml \ --mount=type=bind,source=highscore-api/src,target=highscore-api/src \ --mount=type=bind,source=highscore-api/Cargo.toml,target=highscore-api/Cargo.toml \ + --mount=type=bind,source=highscore-cleanup-job/src,target=highscore-cleanup-job/src \ + --mount=type=bind,source=highscore-cleanup-job/Cargo.toml,target=highscore-cleanup-job/Cargo.toml \ --mount=type=bind,source=highscore-types/src,target=highscore-types/src \ --mount=type=bind,source=highscore-types/Cargo.toml,target=highscore-types/Cargo.toml \ --mount=type=cache,target=/app/target/ \ diff --git a/highscore-api/Dockerfile b/highscore-api/Dockerfile index 98d34e2..80621e6 100644 --- a/highscore-api/Dockerfile +++ b/highscore-api/Dockerfile @@ -11,6 +11,8 @@ RUN --mount=type=bind,source=Cargo.toml,target=Cargo.toml \ --mount=type=bind,source=front-end/Cargo.toml,target=front-end/Cargo.toml \ --mount=type=bind,source=highscore-api/src,target=highscore-api/src \ --mount=type=bind,source=highscore-api/Cargo.toml,target=highscore-api/Cargo.toml \ + --mount=type=bind,source=highscore-cleanup-job/src,target=highscore-cleanup-job/src \ + --mount=type=bind,source=highscore-cleanup-job/Cargo.toml,target=highscore-cleanup-job/Cargo.toml \ --mount=type=bind,source=highscore-types/src,target=highscore-types/src \ --mount=type=bind,source=highscore-types/Cargo.toml,target=highscore-types/Cargo.toml \ --mount=type=cache,target=/app/target/ \ diff --git a/highscore-cleanup-job/Cargo.toml b/highscore-cleanup-job/Cargo.toml new file mode 100644 index 0000000..690303c --- /dev/null +++ b/highscore-cleanup-job/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "highscore-cleanup-job" +version = "0.1.0" +edition = "2021" + +[dependencies] +highscore-types = { path = "../highscore-types" } + +mongodb = { version = "2", features = ["tracing-unstable"] } +bson = { version = "2", features = ["time-0_3"] } +opentelemetry = "0.19" +serde = { version = "1", features = ["derive"] } +tokio = { version = "1", features = ["full"] } +time = { version = "0.3", features = ["parsing", "serde-well-known"] } +tracing = "0.1" +tracing-opentelemetry = "0.19" +tracing-subscriber = "0.3" +init-tracing-opentelemetry = { version = "0.12.0-alpha.0", features = ["tracing_subscriber_ext", "otlp"] } +futures = "0.3" diff --git a/highscore-cleanup-job/Dockerfile b/highscore-cleanup-job/Dockerfile new file mode 100644 index 0000000..8a46b2a --- /dev/null +++ b/highscore-cleanup-job/Dockerfile @@ -0,0 +1,34 @@ +FROM rust:1.70 AS builder +ARG CARGO_INSTALL_OPTIONS='' +WORKDIR /app +# Build the service +# - Uses bind mounts so that it is not needed to copy the source code into the container +# (note that due to using a Cargo workspace the source files for all members members are needed) +# - Uses cache mounts to speed up subsequent builds +RUN --mount=type=bind,source=Cargo.toml,target=Cargo.toml \ + --mount=type=bind,source=Cargo.lock,target=Cargo.lock \ + --mount=type=bind,source=front-end/src,target=front-end/src \ + --mount=type=bind,source=front-end/Cargo.toml,target=front-end/Cargo.toml \ + --mount=type=bind,source=highscore-api/src,target=highscore-api/src \ + --mount=type=bind,source=highscore-api/Cargo.toml,target=highscore-api/Cargo.toml \ + --mount=type=bind,source=highscore-cleanup-job/src,target=highscore-cleanup-job/src \ + --mount=type=bind,source=highscore-cleanup-job/Cargo.toml,target=highscore-cleanup-job/Cargo.toml \ + --mount=type=bind,source=highscore-types/src,target=highscore-types/src \ + --mount=type=bind,source=highscore-types/Cargo.toml,target=highscore-types/Cargo.toml \ + --mount=type=cache,target=/app/target/ \ + --mount=type=cache,target=/usr/local/cargo/registry/ \ + cd highscore-cleanup-job && cargo install ${CARGO_INSTALL_OPTIONS} --locked --path . + +FROM debian:12-slim AS final +RUN apt-get update && apt-get install -y ca-certificates tzdata && rm -rf /var/lib/apt/lists/* +ARG UID=10001 +RUN adduser \ + --disabled-password \ + --home "/nonexistent" \ + --shell "/sbin/nologin" \ + --no-create-home \ + --uid "${UID}" \ + appuser +USER appuser +COPY --from=builder /usr/local/cargo/bin/highscore-cleanup-job /usr/local/bin/ +CMD ["highscore-cleanup-job"] diff --git a/highscore-cleanup-job/src/main.rs b/highscore-cleanup-job/src/main.rs new file mode 100644 index 0000000..5d36ab6 --- /dev/null +++ b/highscore-cleanup-job/src/main.rs @@ -0,0 +1,97 @@ +use std::{collections::HashSet, env, error::Error}; + +use bson::{doc, oid::ObjectId, DateTime}; +use futures::TryStreamExt; +use highscore_types::HighScoreDocument; +use init_tracing_opentelemetry::tracing_subscriber_ext; +use mongodb::{ + options::{ClientOptions, FindOptions}, + Client, Database, +}; +use time::OffsetDateTime; + +const TO_KEEP_COUNT: u8 = 15; + +async fn do_cleanup(db: &Database) -> Result<(), Box> { + let collection = db.collection::("highscore"); + + let find_opts = FindOptions::builder() + .sort(doc! { "score": -1}) + .skip(Some(u64::from(TO_KEEP_COUNT))) + .build(); + + let ok_to_delete_all_time = collection + .find(None, find_opts.clone()) + .await? + .try_collect::>() + .await?; + + let ok_to_delete_all_time = ok_to_delete_all_time + .iter() + .filter_map(|hs| hs.id) + .collect::>(); + + let start_of_this_year = DateTime::builder() + .year(OffsetDateTime::now_utc().year()) + .month(1) + .day(1) + .build()?; + + let ok_to_delete_this_year = collection + .find(doc! { "timestamp": {"$gte": start_of_this_year}}, find_opts) + .await? + .try_collect::>() + .await?; + + let ok_to_delete_this_year = ok_to_delete_this_year + .iter() + .filter_map(|hs| hs.id) + .collect::>(); + + let to_delete = ok_to_delete_this_year + .intersection(&ok_to_delete_all_time) + .copied() + .collect::>(); + + if !to_delete.is_empty() { + tracing::info!(?to_delete, "Ready to delete highscores"); + + let res = collection + .delete_many(doc! { "_id": {"$in": to_delete}}, None) + .await?; + + tracing::info!( + deleted_count = res.deleted_count, + "Successfully deleted no-longer-needed highscores" + ); + } else { + tracing::info!("Nothing to delete"); + } + + Ok(()) +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + tracing_subscriber_ext::init_subscribers()?; + + let db = get_db_handle().await?; + + tracing::info!("Cleanup job started successfully"); + + do_cleanup(&db).await?; + + tracing::info!("Cleanup job completed successfully"); + + Ok(()) +} + +async fn get_db_handle() -> Result { + let connstr = env::var("DB_CONNSTR").unwrap_or_else(|e| { + tracing::warn!(?e, "DB_CONNSTR not set. Defaulting to localhost db."); + String::from("mongodb://root:secret@localhost:27017/") + }); + + let mongo_client = Client::with_options(ClientOptions::parse(connstr).await?)?; + Ok(mongo_client.database("snake-highscore")) +} diff --git a/highscore-types/src/lib.rs b/highscore-types/src/lib.rs index 5360b54..c31bba6 100644 --- a/highscore-types/src/lib.rs +++ b/highscore-types/src/lib.rs @@ -1,3 +1,4 @@ +use bson::oid::ObjectId; use bson::DateTime; use serde::{Deserialize, Serialize}; @@ -10,6 +11,8 @@ pub struct HighScoreDto { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] pub struct HighScoreDocument { + #[serde(rename = "_id", skip_serializing_if = "Option::is_none")] + pub id: Option, pub user_name: String, pub score: u8, pub timestamp: DateTime, @@ -23,6 +26,7 @@ impl HighScoreDocument { Err(format!("Invalid score {}: too high", dto.score)) } else { Ok(HighScoreDocument { + id: None, user_name: dto.user_name.clone(), score: dto.score, timestamp: DateTime::now(), diff --git a/terraform/api.tf b/terraform/api.tf index 3ad2ba4..67d7b30 100644 --- a/terraform/api.tf +++ b/terraform/api.tf @@ -1,10 +1,3 @@ -resource "azurerm_container_app_environment" "containerAppEnv" { - name = "cae-snake-${var.ENVIRONMENT}" - location = data.azurerm_resource_group.rg.location - resource_group_name = data.azurerm_resource_group.rg.name - log_analytics_workspace_id = azurerm_log_analytics_workspace.logWorkspace.id -} - resource "azurerm_container_app" "highscoreApi" { name = "ca-snakehighscoreapi-${var.ENVIRONMENT}" container_app_environment_id = azurerm_container_app_environment.containerAppEnv.id diff --git a/terraform/cleanup-job.tf b/terraform/cleanup-job.tf new file mode 100644 index 0000000..e49a893 --- /dev/null +++ b/terraform/cleanup-job.tf @@ -0,0 +1,20 @@ +# Currently (July 2023) terraform azurerm provider does not support declaring azure container +# app jobs. Azure CLI to the rescue + +resource "null_resource" "createCleanupJob" { + triggers = { + container_app_env = azurerm_container_app_environment.containerAppEnv.id + } + + provisioner "local-exec" { + command = <