From dbee5c28c8d005a149c1976d8da2493a31ef6cba Mon Sep 17 00:00:00 2001 From: Esdras Renan Date: Mon, 17 Nov 2025 14:23:46 -0300 Subject: [PATCH] fix: stabilize convex pagination and ci fallback --- .github/workflows/ci-cd-web-desktop.yml | 63 +++++++++++++++++++------ convex/reports.ts | 51 ++++++++++++-------- 2 files changed, 80 insertions(+), 34 deletions(-) diff --git a/.github/workflows/ci-cd-web-desktop.yml b/.github/workflows/ci-cd-web-desktop.yml index 90d4af4..0843d12 100644 --- a/.github/workflows/ci-cd-web-desktop.yml +++ b/.github/workflows/ci-cd-web-desktop.yml @@ -155,6 +155,7 @@ jobs: id: key run: | echo "Waiting for Convex container..." + CID="" for attempt in $(seq 1 12); do CID=$(docker ps --format '{{.ID}} {{.Names}}' | awk '/sistema_convex_backend/{print $1; exit}') if [ -n "$CID" ]; then @@ -166,14 +167,28 @@ jobs: docker service update --force sistema_convex_backend || true sleep 5 done - if [ -z "$CID" ]; then - echo "No convex container" + CONVEX_IMAGE="ghcr.io/get-convex/convex-backend:latest" + if [ -n "$CID" ]; then + KEY=$(docker exec -i "$CID" /bin/sh -lc './generate_admin_key.sh' | tr -d '\r' | grep -o 'convex-self-hosted|[^ ]*' | tail -n1) + else + echo "No running convex container detected; attempting offline admin key extraction..." + VOLUME="sistema_convex_data" + if docker volume inspect "$VOLUME" >/dev/null 2>&1; then + KEY=$(docker run --rm -v "$VOLUME":/convex/data "$CONVEX_IMAGE" /bin/sh -lc './generate_admin_key.sh' | tr -d '\r' | grep -o 'convex-self-hosted|[^ ]*' | tail -n1) + else + echo "Volume $VOLUME não encontrado; não foi possível extrair a chave admin" + fi + fi + echo "ADMIN_KEY=$KEY" >> $GITHUB_OUTPUT + echo "Admin key acquired? $([ -n "$KEY" ] && echo yes || echo no)" + if [ -z "$KEY" ]; then + docker service ps sistema_convex_backend || true + exit 1 + fi + if [ -z "$KEY" ]; then docker service ps sistema_convex_backend || true exit 1 fi - KEY=$(docker exec -i "$CID" /bin/sh -lc './generate_admin_key.sh' | tr -d '\r' | grep -o 'convex-self-hosted|[^ ]*' | tail -n1) - echo "ADMIN_KEY=$KEY" >> $GITHUB_OUTPUT - echo "Admin key acquired? $([ -n "$KEY" ] && echo yes || echo no)" - name: Copy production .env if present run: | @@ -399,6 +414,7 @@ jobs: id: key run: | echo "Waiting for Convex container..." + CID="" for attempt in $(seq 1 12); do CID=$(docker ps --format '{{.ID}} {{.Names}}' | awk '/sistema_convex_backend/{print $1; exit}') if [ -n "$CID" ]; then @@ -408,14 +424,24 @@ jobs: echo "Attempt $attempt: container not ready yet; sleeping 5s" sleep 5 done - if [ -z "$CID" ]; then - echo "No convex container" + CONVEX_IMAGE="ghcr.io/get-convex/convex-backend:latest" + if [ -n "$CID" ]; then + KEY=$(docker exec -i "$CID" /bin/sh -lc './generate_admin_key.sh' | tr -d '\r' | grep -o 'convex-self-hosted|[^ ]*' | tail -n1) + else + echo "No running convex container detected; attempting offline admin key extraction..." + VOLUME="sistema_convex_data" + if docker volume inspect "$VOLUME" >/dev/null 2>&1; then + KEY=$(docker run --rm -v "$VOLUME":/convex/data "$CONVEX_IMAGE" /bin/sh -lc './generate_admin_key.sh' | tr -d '\r' | grep -o 'convex-self-hosted|[^ ]*' | tail -n1) + else + echo "Volume $VOLUME não encontrado; não foi possível extrair a chave admin" + fi + fi + echo "ADMIN_KEY=$KEY" >> $GITHUB_OUTPUT + echo "Admin key acquired? $([ -n "$KEY" ] && echo yes || echo no)" + if [ -z "$KEY" ]; then docker service ps sistema_convex_backend || true exit 1 fi - KEY=$(docker exec -i "$CID" /bin/sh -lc './generate_admin_key.sh' | tr -d '\r' | grep -o 'convex-self-hosted|[^ ]*' | tail -n1) - echo "ADMIN_KEY=$KEY" >> $GITHUB_OUTPUT - echo "Admin key acquired? $([ -n "$KEY" ] && echo yes || echo no)" - name: Bring convex.json from live app if present run: | @@ -550,6 +576,7 @@ jobs: id: key run: | echo "Waiting for Convex container..." + CID="" for attempt in $(seq 1 12); do CID=$(docker ps --format '{{.ID}} {{.Names}}' | awk '/sistema_convex_backend/{print $1; exit}') if [ -n "$CID" ]; then @@ -559,12 +586,18 @@ jobs: echo "Attempt $attempt: container not ready yet; sleeping 5s" sleep 5 done - if [ -z "$CID" ]; then - echo "No convex container" - docker service ps sistema_convex_backend || true - exit 1 + CONVEX_IMAGE="ghcr.io/get-convex/convex-backend:latest" + if [ -n "$CID" ]; then + KEY=$(docker exec -i "$CID" /bin/sh -lc './generate_admin_key.sh' | tr -d '\r' | grep -o 'convex-self-hosted|[^ ]*' | tail -n1) + else + echo "No running convex container detected; attempting offline admin key extraction..." + VOLUME="sistema_convex_data" + if docker volume inspect "$VOLUME" >/dev/null 2>&1; then + KEY=$(docker run --rm -v "$VOLUME":/convex/data "$CONVEX_IMAGE" /bin/sh -lc './generate_admin_key.sh' | tr -d '\r' | grep -o 'convex-self-hosted|[^ ]*' | tail -n1) + else + echo "Volume $VOLUME não encontrado; não foi possível extrair a chave admin" + fi fi - KEY=$(docker exec -i "$CID" /bin/sh -lc './generate_admin_key.sh' | tr -d '\r' | grep -o 'convex-self-hosted|[^ ]*' | tail -n1) echo "ADMIN_KEY=$KEY" >> $GITHUB_OUTPUT echo "Admin key acquired? $([ -n "$KEY" ] && echo yes || echo no)" - name: List Convex env and set missing diff --git a/convex/reports.ts b/convex/reports.ts index 0508c20..c509c0c 100644 --- a/convex/reports.ts +++ b/convex/reports.ts @@ -200,37 +200,50 @@ type PaginatedResult = { isDone?: boolean; }; +type QueryBuilder = { + paginate?: (options: { cursor: string | null; numItems: number }) => Promise>; + collect?: () => Promise; +}; + async function paginateTickets( - buildQuery: () => { - paginate: (options: { cursor: string | null; numItems: number }) => Promise>; - collect?: () => Promise; - }, + buildQuery: () => QueryBuilder, handler: (doc: T) => void | Promise, pageSize = REPORTS_PAGE_SIZE, ) { - const query = buildQuery(); - if (typeof (query as { paginate?: unknown }).paginate !== "function") { - const collectFn = (query as { collect?: (() => Promise) | undefined }).collect; - if (typeof collectFn !== "function") { - throw new ConvexError("Query does not support paginate or collect"); - } - const docs = await collectFn.call(query); - for (const doc of docs) { - await handler(doc); - } - return; - } let cursor: string | null = null; + while (true) { - const page = await query.paginate({ cursor, numItems: pageSize }); + const query = buildQuery(); + const paginateFn: + | ((options: { cursor: string | null; numItems: number }) => Promise>) + | undefined = query.paginate; + + if (typeof paginateFn !== "function") { + if (cursor !== null) { + throw new ConvexError("Query does not support pagination but cursor was provided"); + } + const collectFn = query.collect; + if (typeof collectFn !== "function") { + throw new ConvexError("Query does not support paginate or collect"); + } + const docs = await collectFn.call(query); + for (const doc of docs) { + await handler(doc); + } + return; + } + + const page: PaginatedResult = await paginateFn.call(query, { cursor, numItems: pageSize }); for (const doc of page.page) { await handler(doc); } - const done = page.done ?? page.isDone ?? !page.continueCursor; + + const continueCursor = page.continueCursor ?? null; + const done = page.done ?? page.isDone ?? !continueCursor; if (done) { break; } - cursor = page.continueCursor ?? null; + cursor = continueCursor; } }