diff --git a/.github/workflows/toolforge-check-lag.yml b/.github/workflows/toolforge-check-lag.yml new file mode 100644 index 0000000..34016c9 --- /dev/null +++ b/.github/workflows/toolforge-check-lag.yml @@ -0,0 +1,38 @@ +name: Toolforge Check Lag +on: + schedule: + - cron: "42 * * * *" + workflow_dispatch: + +jobs: + check_lag: + name: Check Lag + runs-on: ubuntu-latest + + strategy: + max-parallel: 4 + matrix: + tool: ["editgroups"] + + steps: + - name: Configure SSH key + uses: shimataro/ssh-key-action@v2 + with: + key: ${{ secrets.SSH_PRIVATE_KEY }} + known_hosts: ${{ secrets.SSH_KNOWN_HOSTS }} + + - name: Run deployment commands + uses: appleboy/ssh-action@v1.0.3 + with: + host: ${{ vars.SSH_HOST }} + username: ${{ secrets.SSH_USER }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + port: ${{ vars.SSH_PORT }} + request_pty: true + script: | + set -xe + become ${{ matrix.tool }} webservice python3.11 shell -- webservice-python-bootstrap + become ${{ matrix.tool }} webservice python3.11 shell -- ./www/python/venv/bin/python ./www/python/src/manage.py check_lag + if (( $? != 0 )); then + become ${{ matrix.tool }} webservice python3.11 restart + fi diff --git a/.github/workflows/toolforge-deploy.yml b/.github/workflows/toolforge-deploy.yml index 0ee6447..4296296 100644 --- a/.github/workflows/toolforge-deploy.yml +++ b/.github/workflows/toolforge-deploy.yml @@ -36,5 +36,4 @@ jobs: become ${{ matrix.tool }} webservice python3.11 shell -- '$HOME/www/python/venv/bin/python' '$HOME/www/python/src/manage.py' collectstatic --noinput become ${{ matrix.tool }} webservice python3.11 restart become ${{ matrix.tool }} webservice python3.11 status - become ${{ matrix.tool }} ./www/python/src/restart_listener.sh become ${{ matrix.tool }} ./www/python/src/restart_celery.sh diff --git a/deployment/celery.yaml b/deployment/celery.yaml index 271f414..7bb1b8d 100644 --- a/deployment/celery.yaml +++ b/deployment/celery.yaml @@ -1,4 +1,4 @@ -# Run the EventStream listener on kubernetes +# Run Celery on kubernetes apiVersion: apps/v1 kind: Deployment metadata: diff --git a/deployment/listener.yaml b/deployment/listener.yaml deleted file mode 100644 index 980130a..0000000 --- a/deployment/listener.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Run the EventStream listener on kubernetes -apiVersion: apps/v1 -kind: Deployment -metadata: - name: editgroups.listener.sh - namespace: tool-editgroups - labels: - name: editgroups.listener.sh - toolforge: tool -spec: - replicas: 1 - selector: - matchLabels: - name: editgroups.listener.sh - toolforge: tool - template: - metadata: - labels: - name: editgroups.listener.sh - toolforge: tool - spec: - containers: - - name: listener - image: docker-registry.tools.wmflabs.org/toolforge-python311-sssd-base:latest - command: [ "/data/project/editgroups/www/python/src/listener.sh" ] - workingDir: /data/project/editgroups/www/python/src - env: - - name: HOME - value: /data/project/editgroups - imagePullPolicy: Always - diff --git a/deployment/migrator.yaml b/deployment/migrator.yaml deleted file mode 100644 index 8c46152..0000000 --- a/deployment/migrator.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Run the Django migrator on kubernetes -apiVersion: apps/v1 -kind: Deployment -metadata: - name: editgroups.migrator.sh - namespace: tool-editgroups - labels: - name: editgroups.migrator.sh - toolforge: tool -spec: - replicas: 1 - selector: - matchLabels: - name: editgroups.migrator.sh - toolforge: tool - template: - metadata: - labels: - name: editgroups.migrator.sh - toolforge: tool - spec: - containers: - - name: migrator - image: docker-registry.tools.wmflabs.org/toolforge-python39-sssd-base:latest - command: [ "/data/project/editgroups/www/python/src/migrator.sh" ] - workingDir: /data/project/editgroups/www/python/src - env: - - name: HOME - value: /data/project/editgroups - imagePullPolicy: Always - diff --git a/docs/architecture.rst b/docs/architecture.rst index c1a6e1d..5601bb9 100644 --- a/docs/architecture.rst +++ b/docs/architecture.rst @@ -37,7 +37,7 @@ This process can be invoked directly as a script:: python listener.py -Or it can be run as a Kubernetes pod using the ``deployment/listener.yaml`` configuration provided. +It can be run as an `attached daemon to uwsgi `_. In the interest of running EditGroups on other Wikibase instances which do not have an associated EventStream endpoint, it would be great to add the possibility on ingesting edits by polling the recent changes too. diff --git a/docs/install.rst b/docs/install.rst index 57dcae9..7f6c61b 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -129,7 +129,10 @@ Put the following content in ``~/www/python/uwsgi.ini``:: [uwsgi] static-map = /static=/data/project/editgroups/www/python/src/static -and run ``./manage.py collectstatic`` in the ``~/www/python/src`` directory. + master = true + attach-daemon = /data/project/editgroups/www/python/venv/bin/python3 /data/project/editgroups/www/python/src/listener.py + +and run ``./manage.py collectstatic`` in the ``~/www/python/src`` directory. The listener will be an attached dameon, restarting with webservice restart. Configure OAuth login: @@ -156,9 +159,8 @@ Go to the webservice, login with OAuth to the application. This will create a `` user.is_staff = True user.save() -Launch the listener and Celery in Kubernetes. These deployment files may need to be adapted if you are not deploying the tool as the ``editgroups`` toolforge tool but another tool id: +Launch Celery in Kubernetes. These deployment files may need to be adapted if you are not deploying the tool as the ``editgroups`` toolforge tool but another tool id: -- ``kubectl create -f deployment/listener.yaml`` - ``kubectl create -f deployment/celery.yaml`` Backup the database regularly with: diff --git a/listener.sh b/listener.sh deleted file mode 100755 index 2b8010a..0000000 --- a/listener.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -set -e - -VENV_DIR=/data/project/editgroups/www/python/venv - -if [[ -f ${VENV_DIR}/bin/activate ]]; then - source ${VENV_DIR}/bin/activate -else - echo "Creating virtualenv" - rm -rf ${VENV_DIR} - pyvenv ${VENV_DIR} - source ${VENV_DIR}/bin/activate - echo "Installing requirements" - pip install -r requirements.txt -fi; -echo "Launching listener" -python3 listener.py -echo "Listener terminated" diff --git a/migrator.sh b/migrator.sh deleted file mode 100755 index 207fd55..0000000 --- a/migrator.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash - -set -e - -VENV_DIR=/data/project/editgroups/listener_venv - -if [[ -f ${VENV_DIR}/bin/activate ]]; then - source ${VENV_DIR}/bin/activate -else - echo "Creating virtualenv" - rm -rf ${VENV_DIR} - pyvenv ${VENV_DIR} - source ${VENV_DIR}/bin/activate - echo "Installing requirements" - pip install -r requirements.txt -fi; -echo "Launching migrator" -python3 manage.py migrate -echo "Migrator terminated" -sleep 10 diff --git a/restart_listener.sh b/restart_listener.sh deleted file mode 100755 index 7be8851..0000000 --- a/restart_listener.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -kubectl delete deployment editgroups.listener.sh && kubectl create -f /data/project/editgroups/www/python/src/deployment/listener.yaml && kubectl get pods diff --git a/store/management/__init__.py b/store/management/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/store/management/__init__.py @@ -0,0 +1 @@ + diff --git a/store/management/commands/__init__.py b/store/management/commands/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/store/management/commands/__init__.py @@ -0,0 +1 @@ + diff --git a/store/management/commands/check_lag.py b/store/management/commands/check_lag.py new file mode 100644 index 0000000..1d11caa --- /dev/null +++ b/store/management/commands/check_lag.py @@ -0,0 +1,15 @@ +from django.core.management.base import BaseCommand +from django.core.management.base import CommandError + +from store.models import Edit + + +class Command(BaseCommand): + MAX_SECONDS = 3000 + help = f"Exits with 1 if current lag is bigger than {MAX_SECONDS} seconds" + + def handle(self, *args, **options): + lag = Edit.current_lag().total_seconds() + print(f"Current lag: {lag:.2f} seconds") + if lag > 3000: + raise CommandError(f"Current lag is bigger than {self.MAX_SECONDS}")