Skip to content

Langflow Migration: Upgrade with LANGFLOW_LOAD_FLOWS_PATH #9

Langflow Migration: Upgrade with LANGFLOW_LOAD_FLOWS_PATH

Langflow Migration: Upgrade with LANGFLOW_LOAD_FLOWS_PATH #9

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'],
});
}