Langflow Migration: Upgrade with LANGFLOW_LOAD_FLOWS_PATH #9
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: "Langflow Migration: Upgrade with LANGFLOW_LOAD_FLOWS_PATH" | |
| on: | |
| schedule: | |
| - cron: "0 9 * * *" # 06:00 BRT (UTC-3) | |
| workflow_dispatch: | |
| env: | |
| LANGFLOW_PORT: 7860 | |
| LANGFLOW_URL: http://localhost:7860 | |
| PG_USER: langflow | |
| PG_PASSWORD: langflow_test_pw | |
| PG_DB: langflow | |
| FLOW_NAME: "Getting Started: Simple python function applied to each output" | |
| permissions: | |
| contents: read | |
| issues: write | |
| jobs: | |
| upgrade-with-flows: | |
| name: Upgrade latest → nightly with LANGFLOW_LOAD_FLOWS_PATH | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| services: | |
| postgres: | |
| image: postgres:16 | |
| env: | |
| POSTGRES_USER: langflow | |
| POSTGRES_PASSWORD: langflow_test_pw | |
| POSTGRES_DB: langflow | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install dependencies | |
| run: pip install requests | |
| # ── Phase 1: Langflow Latest with LANGFLOW_LOAD_FLOWS_PATH ── | |
| - name: Pull Langflow latest | |
| run: | | |
| docker pull langflowai/langflow:latest | |
| docker inspect langflowai/langflow:latest \ | |
| --format='{{index .RepoDigests 0}}' | tee /tmp/latest-digest.txt | |
| echo "Latest digest: $(cat /tmp/latest-digest.txt)" | |
| - name: Prepare flow directory for LANGFLOW_LOAD_FLOWS_PATH | |
| run: | | |
| mkdir -p /tmp/test-flows | |
| cp tests/assets/flows/flow.json /tmp/test-flows/ | |
| - name: Start Langflow latest with flow pre-loaded | |
| run: | | |
| docker run -d --name langflow \ | |
| --network host \ | |
| -v "/tmp/test-flows:/flows:ro" \ | |
| -e LANGFLOW_DATABASE_URL="postgresql://$PG_USER:$PG_PASSWORD@localhost:5432/$PG_DB" \ | |
| -e LANGFLOW_AUTO_LOGIN=true \ | |
| -e LANGFLOW_SUPERUSER=langflow \ | |
| -e LANGFLOW_SUPERUSER_PASSWORD=langflow123 \ | |
| -e LANGFLOW_STORE=false \ | |
| -e LANGFLOW_LOAD_FLOWS_PATH=/flows \ | |
| langflowai/langflow:latest | |
| - name: Wait for Langflow latest | |
| run: python tests/github-workflows/migration/wait_for_langflow.py --timeout 120 | |
| env: | |
| LANGFLOW_URL: ${{ env.LANGFLOW_URL }} | |
| - name: Verify flow was loaded on latest | |
| run: python tests/github-workflows/migration/verify_upgrade_with_flows.py | |
| env: | |
| LANGFLOW_URL: ${{ env.LANGFLOW_URL }} | |
| EXPECTED_FLOW_NAME: ${{ env.FLOW_NAME }} | |
| - name: Save latest container logs | |
| if: always() | |
| run: docker logs langflow > /tmp/langflow-latest.log 2>&1 || true | |
| # ── Phase 2: Upgrade to Nightly (same DB + same LANGFLOW_LOAD_FLOWS_PATH) ── | |
| - name: Stop Langflow latest | |
| run: docker stop langflow && docker rm langflow | |
| - name: Pull Langflow nightly | |
| run: | | |
| docker pull langflowai/langflow-nightly:latest | |
| docker inspect langflowai/langflow-nightly:latest \ | |
| --format='{{index .RepoDigests 0}}' | tee /tmp/nightly-digest.txt | |
| echo "Nightly digest: $(cat /tmp/nightly-digest.txt)" | |
| - name: Start Langflow nightly with same DB and LANGFLOW_LOAD_FLOWS_PATH | |
| run: | | |
| docker run -d --name langflow \ | |
| --network host \ | |
| -v "/tmp/test-flows:/flows:ro" \ | |
| -e LANGFLOW_DATABASE_URL="postgresql://$PG_USER:$PG_PASSWORD@localhost:5432/$PG_DB" \ | |
| -e LANGFLOW_AUTO_LOGIN=true \ | |
| -e LANGFLOW_SUPERUSER=langflow \ | |
| -e LANGFLOW_SUPERUSER_PASSWORD=langflow123 \ | |
| -e LANGFLOW_STORE=false \ | |
| -e LANGFLOW_LOAD_FLOWS_PATH=/flows \ | |
| langflowai/langflow-nightly:latest | |
| - name: Wait for Langflow nightly (includes DB migration) | |
| run: python tests/github-workflows/migration/wait_for_langflow.py --timeout 180 | |
| env: | |
| LANGFLOW_URL: ${{ env.LANGFLOW_URL }} | |
| - name: Save nightly container logs | |
| if: always() | |
| run: docker logs langflow > /tmp/langflow-nightly.log 2>&1 || true | |
| # ── Phase 3: Verify ─────────────────────────────────────── | |
| - name: Check nightly logs for UniqueViolation errors | |
| run: | | |
| if grep -i "UniqueViolation\|unique constraint\|duplicate key" /tmp/langflow-nightly.log; then | |
| echo "FAIL: UniqueViolation detected in nightly logs after upgrade with LANGFLOW_LOAD_FLOWS_PATH" | |
| exit 1 | |
| else | |
| echo "OK: No UniqueViolation errors found" | |
| fi | |
| - name: Verify flow still accessible after upgrade | |
| run: python tests/github-workflows/migration/verify_upgrade_with_flows.py | |
| env: | |
| LANGFLOW_URL: ${{ env.LANGFLOW_URL }} | |
| EXPECTED_FLOW_NAME: ${{ env.FLOW_NAME }} | |
| # ── Phase 4: Artifacts ─────────────────────────────────── | |
| - name: Upload logs | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: upgrade-with-flows-${{ github.run_number }} | |
| path: | | |
| /tmp/langflow-latest.log | |
| /tmp/langflow-nightly.log | |
| /tmp/latest-digest.txt | |
| /tmp/nightly-digest.txt | |
| - name: Cleanup | |
| if: always() | |
| run: docker stop langflow 2>/dev/null; docker rm langflow 2>/dev/null; true | |
| - name: Close issue on success | |
| if: success() | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const { data: existing } = await github.rest.issues.listForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| labels: 'migration-upgrade-flows', | |
| state: 'open', | |
| }); | |
| if (existing.length > 0) { | |
| const issue = existing[0]; | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| body: [ | |
| `## ✅ Run #${context.runNumber} — ${new Date().toISOString().split('T')[0]}`, | |
| '', | |
| 'Upgrade-with-flows test passed. Closing this issue.', | |
| '', | |
| `[Workflow Run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`, | |
| ].join('\n'), | |
| }); | |
| await github.rest.issues.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue.number, | |
| state: 'closed', | |
| }); | |
| } | |
| - name: Create or update issue on failure | |
| if: failure() | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const latestDigest = fs.existsSync('/tmp/latest-digest.txt') | |
| ? fs.readFileSync('/tmp/latest-digest.txt', 'utf8').trim().slice(-20) | |
| : 'unknown'; | |
| const nightlyDigest = fs.existsSync('/tmp/nightly-digest.txt') | |
| ? fs.readFileSync('/tmp/nightly-digest.txt', 'utf8').trim().slice(-20) | |
| : 'unknown'; | |
| const { data: existing } = await github.rest.issues.listForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| labels: 'migration-upgrade-flows', | |
| state: 'open', | |
| }); | |
| const body = [ | |
| `## Upgrade-with-Flows Failure — Run #${context.runNumber}`, | |
| '', | |
| `- **Date:** ${new Date().toISOString().split('T')[0]}`, | |
| `- **From:** \`langflowai/langflow:latest\` (\`...${latestDigest}\`)`, | |
| `- **To:** \`langflowai/langflow-nightly:latest\` (\`...${nightlyDigest}\`)`, | |
| `- **Scenario:** Upgrade latest → nightly with \`LANGFLOW_LOAD_FLOWS_PATH\` set (flow already in DB)`, | |
| `- **Expected:** Nightly starts cleanly without \`UniqueViolation\``, | |
| '', | |
| `[Workflow Run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`, | |
| '', | |
| '/cc @lice-reis', | |
| ].join('\n'); | |
| if (existing.length > 0) { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: existing[0].number, | |
| body, | |
| }); | |
| } else { | |
| await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: 'Langflow Nightly: Upgrade with LANGFLOW_LOAD_FLOWS_PATH Failed (UniqueViolation)', | |
| body, | |
| labels: ['migration-upgrade-flows', 'automated'], | |
| }); | |
| } |