feat: eliminate useEffect anti-patterns — TanStack Query + declarativ… #483
Workflow file for this run
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
| name: Build | |
| permissions: | |
| contents: read | |
| packages: write | |
| on: | |
| push: | |
| tags: | |
| - "*" | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| environment: Dev | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| ############################################################### | |
| ## Frontend | |
| ############################################################### | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| cache: "npm" | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Install frontend dependencies | |
| working-directory: ./frontend | |
| run: npm ci | |
| - name: Create public directory | |
| working-directory: ./backend | |
| run: mkdir -p src/public | |
| - name: Build frontend | |
| working-directory: ./frontend | |
| run: npm run build | |
| - name: Prune frontend dependencies | |
| working-directory: ./frontend | |
| run: npm prune --production | |
| - name: Save Node dependencies cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| **/node_modules | |
| key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} | |
| ############################################################### | |
| ## Backend | |
| ############################################################### | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - name: Cache Python dependencies | |
| id: cache-python | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pip- | |
| - name: Install dependencies | |
| working-directory: ./backend | |
| run: | | |
| env | sort | |
| pip install --upgrade pip | |
| pip install uv | |
| uv sync --frozen --no-cache --no-dev --extra api | |
| - name: Save Python dependencies cache | |
| if: steps.cache-python.outputs.cache-hit != 'true' | |
| id: save-cache-python | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }} | |
| ############################################################### | |
| ## Docker | |
| ############################################################### | |
| - name: Copy Docker README and LICENSE to backend | |
| run: | | |
| cp docker/README.md backend/README.md | |
| cp LICENSE backend/LICENSE | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ secrets.GHCR_USERNAME || github.actor }} | |
| password: ${{ secrets.GHCR_PAT }} | |
| - name: Build and push API image | |
| working-directory: ./backend | |
| run: | | |
| TAG=${GITHUB_REF#refs/tags/} | |
| docker build --target api \ | |
| -t ghcr.io/ruska-ai/orchestra-api:$TAG \ | |
| -t ghcr.io/ruska-ai/orchestra-api:latest \ | |
| -t ghcr.io/ruska-ai/orchestra:$TAG \ | |
| -t ghcr.io/ruska-ai/orchestra:latest \ | |
| . | |
| docker push ghcr.io/ruska-ai/orchestra-api:$TAG | |
| docker push ghcr.io/ruska-ai/orchestra-api:latest | |
| docker push ghcr.io/ruska-ai/orchestra:$TAG | |
| docker push ghcr.io/ruska-ai/orchestra:latest | |
| - name: Build and push Worker image | |
| working-directory: ./backend | |
| run: | | |
| TAG=${GITHUB_REF#refs/tags/} | |
| docker build --target worker \ | |
| -t ghcr.io/ruska-ai/orchestra-worker:$TAG \ | |
| -t ghcr.io/ruska-ai/orchestra-worker:latest \ | |
| . | |
| docker push ghcr.io/ruska-ai/orchestra-worker:$TAG | |
| docker push ghcr.io/ruska-ai/orchestra-worker:latest | |
| - name: Report image sizes | |
| run: | | |
| echo "## Docker Image Sizes" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Image | Size |" >> $GITHUB_STEP_SUMMARY | |
| echo "|-------|------|" >> $GITHUB_STEP_SUMMARY | |
| docker images ghcr.io/ruska-ai/orchestra-api --format "| API | {{.Size}} |" | head -1 >> $GITHUB_STEP_SUMMARY | |
| docker images ghcr.io/ruska-ai/orchestra-worker --format "| Worker | {{.Size}} |" | head -1 >> $GITHUB_STEP_SUMMARY | |
| deploy: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| environment: Dev | |
| steps: | |
| - name: Deploy to VM | |
| env: | |
| SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }} | |
| SSH_HOST: ${{ secrets.SSH_HOST }} | |
| SSH_USER: ${{ secrets.SSH_USER }} | |
| GHCR_USERNAME: ${{ secrets.GHCR_USERNAME || github.actor }} | |
| GHCR_TOKEN: ${{ secrets.GHCR_PAT }} | |
| GHCR_IMAGE: ghcr.io/${{ github.repository_owner }}/orchestra | |
| run: | | |
| # --------------------------------------------------- | |
| # Setup SSH | |
| # --------------------------------------------------- | |
| mkdir -p ~/.ssh | |
| echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa | |
| chmod 600 ~/.ssh/id_rsa | |
| ssh-keyscan github.com >> ~/.ssh/known_hosts | |
| ssh-keyscan -H $SSH_HOST >> ~/.ssh/known_hosts | |
| TAG=${{ github.ref_name }} | |
| # --------------------------------------------------- | |
| # SSH into the server and execute deployment | |
| # --------------------------------------------------- | |
| ssh -i ~/.ssh/id_rsa $SSH_USER@$SSH_HOST " | |
| set -e # Exit on error | |
| cd ~/agent_api | |
| echo '--- Logging into GHCR ---' | |
| echo \"$GHCR_TOKEN\" | docker login ghcr.io -u \"$GHCR_USERNAME\" --password-stdin | |
| echo '--- Pulling new images ---' | |
| docker pull $GHCR_IMAGE-api:$TAG | |
| docker pull $GHCR_IMAGE-worker:$TAG | |
| echo '--- Starting staging container (graphchat_new) on port 8006 ---' | |
| docker stop graphchat_new 2>/dev/null || true | |
| docker rm graphchat_new 2>/dev/null || true | |
| docker run -d \ | |
| --name graphchat_new \ | |
| --network graphchat_default \ | |
| --env-file ./backend/.env \ | |
| -p 8006:8000 \ | |
| $GHCR_IMAGE-api:$TAG | |
| echo '--- Waiting a few seconds for startup ---' | |
| sleep 10 | |
| echo '--- Health check on staging container (graphchat_new) ---' | |
| for i in {1..3}; do | |
| if curl -f http://localhost:8006/api/info; then | |
| echo 'New container on port 8006 is healthy!' | |
| break | |
| else | |
| echo \"Attempt \$i failed. Waiting 10 seconds before retry...\" | |
| sleep 10 | |
| if [ \$i -eq 3 ]; then | |
| echo 'All retry attempts failed.' | |
| exit 1 | |
| fi | |
| fi | |
| done | |
| echo '--- Stopping and removing old container (graphchat) if it exists ---' | |
| docker stop graphchat || true | |
| docker rm graphchat || true | |
| echo '--- Stopping and removing staging container (graphchat_new) ---' | |
| docker stop graphchat_new 2>/dev/null || true | |
| docker rm graphchat_new 2>/dev/null || true | |
| echo '--- Running new container on production port (8005) as graphchat ---' | |
| docker run -d \ | |
| --name graphchat \ | |
| --network graphchat_default \ | |
| --restart always \ | |
| --env-file ./backend/.env \ | |
| -e APP_VERSION=$TAG \ | |
| -e VITE_APP_VERSION=$TAG \ | |
| -p 8005:8000 \ | |
| $GHCR_IMAGE-api:$TAG | |
| echo '--- Ensuring redis7 is on graphchat_default network ---' | |
| docker network connect graphchat_default redis7 2>/dev/null || echo 'redis7 already on network or not found' | |
| echo '--- Stopping and removing old worker container if it exists ---' | |
| docker stop graphchat_worker 2>/dev/null || true | |
| docker rm graphchat_worker 2>/dev/null || true | |
| echo '--- Starting worker container ---' | |
| docker run -d \ | |
| --name graphchat_worker \ | |
| --network graphchat_default \ | |
| --restart always \ | |
| --env-file ./backend/.env \ | |
| -e DISTRIBUTED_WORKERS=true \ | |
| -e REDIS_URL=redis://redis7:6379/0 \ | |
| -e DB_POOL_MIN_SIZE=1 \ | |
| -e DB_POOL_MAX_SIZE=5 \ | |
| --memory=1g \ | |
| --cpus=1 \ | |
| $GHCR_IMAGE-worker:$TAG | |
| echo '--- Worker deployment complete ---' | |
| echo '--- Cleaning up old images ---' | |
| docker system prune -a --filter \"until=1h\" -f | |
| echo '--- Deployment successful! ---' | |
| " |