2 Commits

Author SHA1 Message Date
9b0821926c fix for cluster manager
Some checks failed
Build and deploy the backend to staging / Build and push image (pull_request) Successful in 2m11s
Run linting on the backend code / Build (pull_request) Failing after 2m22s
Run testing on the backend code / Build (pull_request) Failing after 2m26s
Build and deploy the backend to staging / Deploy to staging (pull_request) Failing after 3h3m27s
2025-11-20 18:48:26 +01:00
0514fa063f suggested fix to avoid UnboundLocalError 2025-11-20 18:47:34 +01:00
12 changed files with 115 additions and 104 deletions

1
.envrc
View File

@@ -1 +0,0 @@
use nix

View File

@@ -3,9 +3,6 @@ on:
tags:
- v*
permissions:
pull-requests: write
name: Build and deploy the backend to production
jobs:
@@ -13,7 +10,15 @@ jobs:
name: Build and push image
uses: ./.gitea/workflows/workflow_build-image.yaml
with:
# sets the tag to the git tag that triggered the workflow - the deployment (configured in a separate repository) will use this tag and be deployed to production by argocd
tag: ${{ github.ref_name }}
tag: stable
secrets:
PACKAGE_REGISTRY_ACCESS: ${{ secrets.PACKAGE_REGISTRY_ACCESS }}
deploy-prod:
name: Deploy to production
uses: ./.gitea/workflows/workflow_deploy-container.yaml
with:
overlay: prod
secrets:
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
needs: build-and-push

View File

@@ -12,32 +12,15 @@ jobs:
name: Build and push image
uses: ./.gitea/workflows/workflow_build-image.yaml
with:
# sets a unique tag for each commit in the PR - this gets deployed to a separate application instance using argocd
tag: sha${{ github.sha }}
tag: unstable
secrets:
PACKAGE_REGISTRY_ACCESS: ${{ secrets.PACKAGE_REGISTRY_ACCESS }}
notify:
runs-on: ubuntu-latest
name: Add a comment to the PR to notify about the deployment
steps:
- name: Download gitea client
run: |
curl -sSL -o tea https://dl.gitea.com/tea/0.11.0/tea-0.11.0-linux-amd64
chmod +x tea
- name: Login
run: |
./tea login add --url git.kluster.moll.re --name bot --token ${{ secrets.GITEA_TOKEN }}
./tea login default
- name: Post comment
run: |
./tea comment --repo anydev/anyway --login bot ${{ github.event.number }} """
The backend has been deployed to staging with url https://pr-${{ github.event.number }}.anyway-stg.anydev.info. Check the deployment status in ArgoCD:
[![App Status](https://argocd.kluster.moll.re/api/badge?name=anydev-anyway-backend-stg-pr-${{ github.event.number }}&revision=true&showAppName=true)](https://argocd.kluster.moll.re/applications/anydev-anyway-backend-stg-pr-${{ github.event.number }})
"""
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_BASE_URL: ${{ secrets.GITEA_BASE_URL }}
GITEA_REPO: ${{ secrets.GITEA_REPO }}
deploy-prod:
name: Deploy to staging
uses: ./.gitea/workflows/workflow_deploy-container.yaml
with:
overlay: stg
secrets:
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
needs: build-and-push

View File

@@ -0,0 +1,35 @@
on:
workflow_call:
inputs:
overlay:
required: true
type: string
secrets:
KUBE_CONFIG:
required: true
name: Deploy the newly built container
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
steps:
- uses: https://gitea.com/actions/checkout@v4
with:
submodules: true
- name: setup kubectl
uses: https://github.com/azure/setup-kubectl@v4
- name: Set kubeconfig
run: |
echo "${{ secrets.KUBE_CONFIG }}" > kubeconfig
- name: Deploy to k8s
run: |
kubectl apply -k backend/deployment/overlays/${{ inputs.overlay }} --kubeconfig=kubeconfig
kubectl -n anyway-backend rollout restart deployment/anyway-backend-${{ inputs.overlay }} --kubeconfig=kubeconfig

1
.gitignore vendored
View File

@@ -1,2 +1 @@
cache/
.direnv/

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "backend/deployment"]
path = backend/deployment
url = https://git.kluster.moll.re/anydev/anyway-backend-deployment

8
.vscode/launch.json vendored
View File

@@ -9,7 +9,9 @@
"name": "Backend - debug",
"type": "debugpy",
"request": "launch",
"envFile": "${workspaceFolder}/backend/debug.env",
"env": {
"DEBUG": "true"
},
"jinja": true,
"cwd": "${workspaceFolder}/backend",
"module": "fastapi",
@@ -23,7 +25,9 @@
"type": "debugpy",
"request": "launch",
"program": "src/tester.py",
"envFile": "${workspaceFolder}/backend/debug.env",
"env": {
"DEBUG": "true"
},
"cwd": "${workspaceFolder}/backend"
},
// frontend - flutter app

View File

@@ -1,3 +0,0 @@
{
"nixEnvSelector.nixFile": "${workspaceFolder}/default.nix"
}

5
backend/.gitignore vendored
View File

@@ -1,6 +1,3 @@
# all .env files
*.env
# osm-cache
cache_XML/
@@ -168,4 +165,4 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
#.idea/

1
backend/deployment Submodule

Submodule backend/deployment added at 904f16bfc0

View File

@@ -102,52 +102,57 @@ class ClusterManager:
selector = sel,
out = out
)
except Exception as e:
self.logger.warning(f"Error fetching clusters: {e}")
if result is None :
self.logger.debug(f"Found no {cluster_type} clusters, overpass query returned no datapoints.")
self.valid = False
else :
points = []
for elem in result:
osm_type = elem.get('type')
# Get coordinates and append them to the points list
_, coords = get_base_info(elem, osm_type)
if coords is not None :
points.append(coords)
if points :
self.all_points = np.array(points)
# Apply DBSCAN to find clusters. Choose different settings for different cities.
if self.cluster_type == 'shopping' and len(self.all_points) > 200 :
dbscan = DBSCAN(eps=0.00118, min_samples=15, algorithm='kd_tree') # for large cities
elif self.cluster_type == 'sightseeing' :
dbscan = DBSCAN(eps=0.0025, min_samples=15, algorithm='kd_tree') # for historic neighborhoods
else :
dbscan = DBSCAN(eps=0.00075, min_samples=10, algorithm='kd_tree') # for small cities
labels = dbscan.fit_predict(self.all_points)
# Check that there are is least 1 cluster
if len(set(labels)) > 1 :
self.logger.info(f"Found {len(set(labels))} different {cluster_type} clusters.")
# Separate clustered points and noise points
self.cluster_points = self.all_points[labels != -1]
self.cluster_labels = labels[labels != -1]
self.filter_clusters() # ValueError here sometimes. I dont know why. # Filter the clusters to keep only the largest ones.
self.valid = True
else :
self.logger.info(f"Found 0 {cluster_type} clusters.")
self.valid = False
if result is None :
self.logger.debug(f"Found no {cluster_type} clusters, overpass query returned no datapoints.")
self.valid = False
else :
self.logger.debug(f"Detected 0 {cluster_type} clusters.")
self.valid = False
points = []
for elem in result:
osm_type = elem.get('type')
# Get coordinates and append them to the points list
_, coords = get_base_info(elem, osm_type)
if coords is not None :
points.append(coords)
if points :
self.all_points = np.array(points)
# Apply DBSCAN to find clusters. Choose different settings for different cities.
if self.cluster_type == 'shopping' and len(self.all_points) > 200 :
dbscan = DBSCAN(eps=0.00118, min_samples=15, algorithm='kd_tree') # for large cities
elif self.cluster_type == 'sightseeing' :
dbscan = DBSCAN(eps=0.0025, min_samples=15, algorithm='kd_tree') # for historic neighborhoods
else :
dbscan = DBSCAN(eps=0.00075, min_samples=10, algorithm='kd_tree') # for small cities
labels = dbscan.fit_predict(self.all_points)
# Check that there are is least 1 cluster
if len(set(labels)) > 1 :
self.logger.info(f"Found {len(set(labels))} different {cluster_type} clusters.")
# Separate clustered points and noise points
self.cluster_points = self.all_points[labels != -1]
self.cluster_labels = labels[labels != -1]
self.filter_clusters() # ValueError here sometimes. I dont know why. # Filter the clusters to keep only the largest ones.
self.valid = True
else :
self.logger.info(f"Found 0 {cluster_type} clusters.")
self.valid = False
else :
self.logger.debug(f"Detected 0 {cluster_type} clusters.")
self.valid = False
except UnboundLocalError as ule:
self.logger.warning(f"Error fetching clusters due to overpass crash: {ule}")
self.valid = False
except Exception as e:
self.logger.warning(f"Error fetching clusters: {e}")
raise Exception from e
def generate_clusters(self) -> list[Landmark]:

View File

@@ -1,17 +0,0 @@
{ pkgs ? import <nixpkgs> { config.android_sdk.accept_license = true; config.allowUnfree = true; } }:
pkgs.mkShell {
buildInputs = [
pkgs.flutter
#pkgs.android-tools # for adb
#pkgs.openjdk # required for Android builds
];
# Set up Android SDK paths if needed
shellHook = ''
export ANDROID_SDK_ROOT=${pkgs.androidsdk}/libexec/android-sdk
export PATH=$PATH:${pkgs.androidsdk}/libexec/android-sdk/platform-tools
echo "Flutter dev environment ready. 'adb' and 'flutter' are available."
'';
}