Forgejo adatbázis karbantartás: ugyan, mi baj lehet?

Mint kiderült, elég sok minden. Elmesélem, hogy mit miért csináltam, és hogy mit kellett volna helyette.

Forgejo ikon
Forgejo ikon

Mint kiderült, elég sok minden. Elmesélem, hogy mit miért csináltam, és hogy mit kellett volna helyette.

Előzmények

A Forgejo egy szoftverfejlesztési platform („software forge”), ami magába foglalja a verziókezelést (git), hibakövetést, a beolvasztási kérelmek (pull request) kezelését, a dokumentációt Wiki oldal személyében, a csomag- és kiadáskezelést, a projekt menedzsmentet. Természetesen képes bizonyos események bekövetkezése esetén előre meghatározott műveletek elvégzésére is.

Képességeit tekintve mondhatjuk, hogy egy helyben futtatható GitHub, mely nem mellékesen szabad szoftver. Kisebb módosításokkal Forgejo fut a Codeberg platform alatt is.

Ki ne akarna egy ilyet otthonra, ugye?

A Forgejo a Gitea (immár hard) forkja. Amikor mi itthon elkezdtük használni, akkor még láthatáron sem volt az a cécó, ami miatt megszületett a Forgejo, így mi még a Giteát kezdtük használni. A forknak már lassan 4 éve, mi pedig olyan 5 éve használjuk.

Ez az öt év nyomot hagyott a rendszeren: a számtalan alkalmazásfrissítés, a megannyi PostgreSQL upgrade, az átállás Giteáról Forgejóra, a különböző konfigurálgatások, próbálkozások, félresikerült tesztek és egyebek kísérik ezt az időszakot. Szó se róla, eddig egész jól tűrte a megpróbáltatásokat.

De az utóbbi hónapokban elkezdtek megszaporodni a lassan lefutó lekérdezésekre figyelmeztető üzenetek, amik azért is voltak furcsák, mert tipikusan olyan adatbázis táblákat érintettek, amikben nagyon kevés adat van: legfeljebb egy tucatnyi sor, de az action_runner pl. 4 (négy) sort tartalmaz, mégis lassan lefutó lekérdezésekre panaszkodott a Forgejo. Valami három másodperc volt egy SELECT ezen a négy soron. Ekkora adatmennyiségnél ezt a sebességet én is hozom egy fehér lapon.

A monitoring szerint nincs semmi látnivaló, minden rendben van. Nincs tele a memória, se magas CPU terhelés, se nagy diszk I/O nincs. Semmi sem indokolja ezt a lassúságot. Természetesen megpróbáltam az ilyenkor megszokott szépségtapaszokat is: kézzel futtatni a full vacuum-ot, újraépíteni az indexeket, de semmi hatásuk nem volt.

Más táblákat is megnézve kiderült, hogy van olyan hogy két index van egy táblán, amik ugyanazt csinálják... csak más a nevük. Akkor most melyiket töröljem? Mivel nem töröm el a dolgokat? A múlt miféle maradványa van még a DB-ben? Megannyi kínzó kérdés.

Arról nem is beszélve, hogy ideje lenne a PostgreSQL-t is frissíteni a 18-as főverzióra, és jó lenne, ha a frissítés már egy optimalizált adatbázissal menne.

Szóval itt az ideje egy nagyobb karbantartásnak.

Forgejo doktor

Ha Forgejo göthös, akkor a doktorhoz érdemes először fordulni: a forgejo doctor check parancs megpróbálja diagnosztizálni a problémát, a --fix argumentummal pedig gyógyítani. Érdemes megemlíteni, hogy alapértelmezetten csak néhány kiválasztott ellenőrzés fut le, a teljes diagnosztikához az --all kapcsoló használata szükséges.

A check mellett van olyan parancs is, hogy recreate-table. A súgója azt mondja, hogy a Forgejo verziók közötti táblastruktúra változásainak lekövetésére való: létrehozza a XORM definíciókból az új táblákat, átmásolja az adatokat majd törli a régi táblákat. Így nem maradnak felesleges használaton kívüli oszlopok (és indexek és egyebek).

Pont ez kell nekem.

A dokumentáció azt is mondja, hogy futtatás előtt illik adatbázismentést csinálni. Kettőt tippelhetsz, hogy csináltam-e, de egy is elég lesz.

Ugyanakkor arról nincs szó, hogy ezt a műveletet offline, tehát a Forgejo leállított állapotában kellene végezni, így nem állítottam le. Eszembe se jutott.

Így lefuttattam a forgejo doctor recreate-table parancsot.

A műtét sikerült, a beteg meghalt

Váratlanul gyorsan, kb. egy percen belül lefutott minden. Mondom faja, ez gyors volt, jöhet is a PostgreSQL upgrade, csak még kattogtatok párat a UI-on és gyorsan csekkolom a logokat.

Látszólag minden rendben volt.

Ennek örömére megcsináltam a PostgreSQL frissítést is. Az szépen és unalmasan lement.

Nem mondom meg, hogy rossz az adatbázis, de lesznek jelei

Egy másik, kapcsolódó projekt, hogy átállok a Sonatype Nexusról Forgejóra mint a helyi PyPI index és Docker registry (és valami másra, ami PyPI index proxy és Docker registry proxy-ként képes működni). A Nexus kiadásról-kiadásra egyre rosszabb, egyre lassabb, folyamatosan eszi a CPU-t, most épp ott tartunk hogy minimális használat mellett 6 óra után 14 GB-ot írt a diszkre. Csak nem tudni, hogy mit. A másik baja, hogy kb. 20 GB adat van benne, de ehhez ~460 GB-ot kér. Próbáltam én mindenféle kompaktálást, ellenőrzést, takarítást, mindent a kérdéses repón, de nincs hatása. A múltkori elcsesződött OrientDB → H2 adatbázis migrációról vagy a kikényszerített használati limitekről már csak halkan teszek említést.

Szóval átállítottam az egyik Docker image készítő pipeline-omat, hogy Forgejóba töltse fel az elkészült lemezképet. Igen ám, de a Forgejo HTTP 500-at kezdett dobálgatni. Vagy 404-et. Mivel néhány napja már egy másik image-et sikerült feltölteni, gondoltam én rontok el valamit. Némi sikertelen hibakeresés után gondoltam generálok egy új tokent a feltöltésekre, lehet az előző túl szigorú lett.

Aha, csak a token létrehozás is HTTP 500-ba torkollott. Na, ilyen még nem volt.

Szóval felcsaptam a Forgejo naplózást. Olyan csúnya hibák voltak benne, amikkel kisgyerekeket lehetne ijesztgetni: memóriahiba, SQL hiba, teljes összeomlások.

Mindig lehet rosszabb. És lesz is.

Az első SQL hiba láttán tudtam, hogy elő kell venni az adatbázismentést. Pont azt, amiről a dokumentáció szólt. Jaa, hogy nincs ilyen. Üdvözlet a következő nehézségi szinten.

A hibaüzeneteket jobban megnézve azok tele voltak tmp_recreate__ kezdetű megszorítások hibáival. Pl.:

ERROR: duplicate key value violates unique constraint "tmp_recreate__package_property_pkey" (SQLSTATE 23505)

Nahát, vajon honnan is jöhetnek? Persze, hogy a forgejo doctorral ketten követtük el a hibát: én nem állítottam le a Forgejót, ő meg nem csinálta meg jól a karbantartást.

Kis naivan gondoltam, hogy majd a forgejo doctor check --fix megjavítja a dolgokat. Végül is, erre való, ugye? Ugye?

Igazából nem tudom, miben reménykedtem, de a helyzet annyiban lett még rosszabb, hogy elkezdett olyan táblákat is hiányolni a Forgejo (versions), amik benne voltak (még?) az adatbázisban.

A mi működik és mi nem alapján kiderült, hogy szépen fokozatosan minden meg fog purcanni, mert egyre több helyen kaptam HTTP 500-at, egyre többször jött SQL hiba.

Amit akkor nem tudtam mire vélni – és ami félre is vitt – hogyha ugyanazt a műveletet 2x - 3x újrapróbálom, akkor van amikor működik. 10-ből egyszer szinte biztosan.

Néha nekem is lehet szerencsém

A PostgreSQL upgrade pont jókor jött: a frissítési folyamat során teljes mentést készítünk az adatbázisról és azt töltjük be az új verzióba. Az adat így 2x is megvan: a régi (már nem futó) adatbázisban és a mentésben is. Igaz, hogy ez az adat már a forgejo doctor káoszosítása utáni, de valószínűleg a konzisztencia nem romlott el a pár kattintás után. Ugyanis utána egyből kapcsoltam is le mindent a frissítéshez.

Szóval a terv:

  1. Visszaindítom a régebbi PostgreSQL-t, kimentem csak az adatokat az összes táblából, majd leállítom azt.
  2. Az új PostgreSQL-ben létrehozok egy új, teljesen üres adatbázist
  3. A Forgejo létrehozza benne a táblákat, indexeket, megszorításokat, mindent, mintha csak egy friss telepítés lenne
  4. Leállítom a Forgejót, majd mentésből csak az adatokat, 1 sor 1 INSERT alapon betöltöm.
  5. Némi reménykedés, hogy a külső kulcsokkal (foreign keys) és a megszorításokkal nem lesz gond az INSERT utasítások során. Hátha gondolt erre a pg_dump.
  6. Profit?

Az első három lépés gyorsan végigment. A negyedik, a mentés betöltése viszont sokkal lassabb volt a vártál. Minimális I/O és CPU terhelés mellett, ~350 MB betöltése 2,5 órán át tartott. Bealudtam a folyamat alatt.

De sikerült.

Mármint, sikeresen végigment.

A másnap reggel

Indítom a Forgejót, látszólag rendben van. Megyek, indítanék egy elmaradt Actiont, erre… HTTP 500. Megnézem a logokat, hát sírva fakadok:

2026/05/10 09:54:53 ...po/actions/manual.go:56:ManualRunWorkflow() [E] workflow.Dispatch: unique constraint violation: ERROR: duplicate key value violates unique constraint "action_run_pkey" (SQLSTATE 23505)

Legalább hivatalosan szar, nem pedig valami ideiglenes doktor által tákolt megszorítás miatt.

Az action_run_pkey a lehető legegyszerűbb elsődleges-kulcsmegszorítás: az action_run tábla id oszlopára van rákötve, aminek egy számnak kell lennie és nyilván nem lehet belőle kettő ugyanolyan.

De mégis, mi az az INSERT, ami ezt okozza?

Ehhez be kell kapcsolni az SQL kifejezések naplózását. Ez a beállítás a <forgejo_könyvtár>/conf/app.ini -ben van, ahol a [database] szekció LOG_SQL értékét kell true-ra állítani és újraindítani a Forgejót.

2026/05/10 09:54:53 models/db/context.go:239:Insert() [E] [Error SQL Query] INSERT INTO "action_run" ("title","repo_id","owner_id","workflow_id","workflow_directory","index","trigger_user_id","schedule_id","ref","commit_sha","event","event_payload","trigger_event","status","version","started","stopped","previous_duration","created","updated","notify_email","is_fork_pull_request","pull_request_poster_id","pull_request_id","need_approval","approved_by","concurrency_group","concurrency_type","pre_execution_error","pre_execution_error_code","pre_execution_error_details") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31) RETURNING "id" [<értékek>....]

De ebben nincs benne az id oszlop, ami a gondot okozza, viszont az INSERT végén kéri a létrejött sor id oszlopának értékét.

Tehát az id-t a PostgreSQL generálja. De miért generál magának rossz számot, hát bolond ez?

A PostgreSQL log azt mondja, hogy:

2026-05-10 09:47:55.495 UTC [6535] ERROR:  duplicate key value violates unique constraint "action_run_pkey"
2026-05-10 09:47:55.495 UTC [6535] DETAIL:  Key (id)=(10) already exists.

Az automatika néhányszor még bepróbálkozott:

2026-05-10 09:48:04.429 UTC [6535] ERROR:  duplicate key value violates unique constraint "action_run_pkey"
2026-05-10 09:48:04.429 UTC [6535] DETAIL:  Key (id)=(11) already exists.
---
2026-05-10 09:54:53.901 UTC [6707] ERROR:  duplicate key value violates unique constraint "action_run_pkey"
2026-05-10 09:54:53.901 UTC [6707] DETAIL:  Key (id)=(12) already exists.

Na jó, kapcsoljuk ki a Forgejót, mielőtt még minden megint összekuszálódna.

Te szent... szekvencia!

A PostgreSQL nem a táblából nézi ki a következő számot, hanem egy beállított szekvencia alapján generálja. A fentiekből látszik, hogy a szekvencia értéke van elcsúszva. Abból indultam ki, hogy a sorról-sorra beszúrás majd mindent megold. Hát nem.

Az action_run id oszlopa 22 ezer magasságában járt, de kapcsolódó action_run_id_seq viszont csak 13-nál.

Rendben, növeljük meg a szekvencia aktuális értékét és ok-thx-bye. Vagyis inkább mégsem, mert mi van, ha a többi szekvencia is elölről indul? Van 115 darab, biztosra kéne menni, hogy rendben lesznek, de hogy én ezt nem fogom manuálisan ellenőrizni, az is hótzicher.

Szia AI

Kedves ChatGPT, kellene egy SQL script, mely megnézi, hogy a sémában lévő szekvenciák megfelelő értéken állnak-e.

Tessék:

DO $$
DECLARE
    r RECORD;
    max_id BIGINT;
    seq_last BIGINT;
BEGIN
    FOR r IN
        SELECT
            ns.nspname AS schema_name,
            seq.relname AS sequence_name,
            tab.relname AS table_name,
            col.attname AS column_name
        FROM pg_class seq
        JOIN pg_namespace ns
            ON ns.oid = seq.relnamespace
        JOIN pg_depend dep
            ON dep.objid = seq.oid
        JOIN pg_class tab
            ON dep.refobjid = tab.oid
        JOIN pg_attribute col
            ON col.attrelid = tab.oid
           AND col.attnum = dep.refobjsubid
        WHERE seq.relkind = 'S'
          AND ns.nspname = 'public'
    LOOP

        EXECUTE format(
            'SELECT COALESCE(MAX(%I), 0) FROM %I.%I',
            r.column_name,
            r.schema_name,
            r.table_name
        )
        INTO max_id;

        EXECUTE format(
            'SELECT last_value FROM %I.%I',
            r.schema_name,
            r.sequence_name
        )
        INTO seq_last;

        RAISE NOTICE
            'Table: %.%, Sequence: %, MAX(id)=%, last_value=%',
            r.table_name,
            r.column_name,
            r.sequence_name,
            max_id,
            seq_last;

        IF seq_last < max_id THEN
            RAISE WARNING
                'Sequence % is behind table data!',
                r.sequence_name;
        END IF;

    END LOOP;
END
$$;

Kimenet:

NOTICE:  Table: version.id, Sequence: version_id_seq, MAX(id)=1, last_value=1
NOTICE:  Table: forgejo_version.id, Sequence: forgejo_version_id_seq, MAX(id)=1, last_value=1
NOTICE:  Table: dbfs_meta.id, Sequence: dbfs_meta_id_seq, MAX(id)=22168, last_value=1
WARNING:  Sequence dbfs_meta_id_seq is behind table data!
NOTICE:  Table: dbfs_data.id, Sequence: dbfs_data_id_seq, MAX(id)=62424, last_value=1
WARNING:  Sequence dbfs_data_id_seq is behind table data!
NOTICE:  Table: access_token.id, Sequence: access_token_id_seq, MAX(id)=18, last_value=1
WARNING:  Sequence access_token_id_seq is behind table data!
NOTICE:  Table: oauth2_application.id, Sequence: oauth2_application_id_seq, MAX(id)=3, last_value=3
NOTICE:  Table: oauth2_authorization_code.id, Sequence: oauth2_authorization_code_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: oauth2_grant.id, Sequence: oauth2_grant_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: login_source.id, Sequence: login_source_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: two_factor.id, Sequence: two_factor_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: webauthn_credential.id, Sequence: webauthn_credential_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: abuse_report.id, Sequence: abuse_report_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: abuse_report_shadow_copy.id, Sequence: abuse_report_shadow_copy_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: secret.id, Sequence: secret_id_seq, MAX(id)=7, last_value=1
WARNING:  Sequence secret_id_seq is behind table data!
NOTICE:  Table: notice.id, Sequence: notice_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: system_setting.id, Sequence: system_setting_id_seq, MAX(id)=3, last_value=1
WARNING:  Sequence system_setting_id_seq is behind table data!
NOTICE:  Table: hook_task.id, Sequence: hook_task_id_seq, MAX(id)=50912, last_value=1
WARNING:  Sequence hook_task_id_seq is behind table data!
NOTICE:  Table: webhook.id, Sequence: webhook_id_seq, MAX(id)=3873, last_value=1
WARNING:  Sequence webhook_id_seq is behind table data!
NOTICE:  Table: federation_host.id, Sequence: federation_host_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: badge.id, Sequence: badge_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: user_badge.id, Sequence: user_badge_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: forgejo_blocked_user.id, Sequence: forgejo_blocked_user_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: email_address.id, Sequence: email_address_id_seq, MAX(id)=4, last_value=1
WARNING:  Sequence email_address_id_seq is behind table data!
NOTICE:  Table: follow.id, Sequence: follow_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: user_open_id.id, Sequence: user_open_id_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: user_redirect.id, Sequence: user_redirect_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: user_setting.id, Sequence: user_setting_id_seq, MAX(id)=1, last_value=1
NOTICE:  Table: user.id, Sequence: user_id_seq, MAX(id)=5, last_value=1
WARNING:  Sequence user_id_seq is behind table data!
NOTICE:  Table: federated_user.id, Sequence: federated_user_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: federated_user_follower.id, Sequence: federated_user_follower_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: repo_archive_download_count.id, Sequence: repo_archive_download_count_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: repo_archiver.id, Sequence: repo_archiver_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: attachment.id, Sequence: attachment_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: language_stat.id, Sequence: language_stat_id_seq, MAX(id)=105, last_value=1
WARNING:  Sequence language_stat_id_seq is behind table data!
NOTICE:  Table: mirror.id, Sequence: mirror_id_seq, MAX(id)=2, last_value=1
WARNING:  Sequence mirror_id_seq is behind table data!
NOTICE:  Table: push_mirror.id, Sequence: push_mirror_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: repo_redirect.id, Sequence: repo_redirect_id_seq, MAX(id)=7, last_value=1
WARNING:  Sequence repo_redirect_id_seq is behind table data!
NOTICE:  Table: release.id, Sequence: release_id_seq, MAX(id)=59, last_value=1
WARNING:  Sequence release_id_seq is behind table data!
NOTICE:  Table: repository.id, Sequence: repository_id_seq, MAX(id)=42, last_value=1
WARNING:  Sequence repository_id_seq is behind table data!
NOTICE:  Table: forgejo_repo_flag.id, Sequence: forgejo_repo_flag_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: repo_indexer_status.id, Sequence: repo_indexer_status_id_seq, MAX(id)=39, last_value=1
WARNING:  Sequence repo_indexer_status_id_seq is behind table data!
NOTICE:  Table: following_repo.id, Sequence: following_repo_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: repo_unit.id, Sequence: repo_unit_id_seq, MAX(id)=686, last_value=1
WARNING:  Sequence repo_unit_id_seq is behind table data!
NOTICE:  Table: star.id, Sequence: star_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: topic.id, Sequence: topic_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: upload.id, Sequence: upload_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: watch.id, Sequence: watch_id_seq, MAX(id)=141, last_value=1
WARNING:  Sequence watch_id_seq is behind table data!
NOTICE:  Table: action_artifact.id, Sequence: action_artifact_id_seq, MAX(id)=2, last_value=1
WARNING:  Sequence action_artifact_id_seq is behind table data!
NOTICE:  Table: action_run.id, Sequence: action_run_id_seq, MAX(id)=22893, last_value=13
WARNING:  Sequence action_run_id_seq is behind table data!
NOTICE:  Table: action_run_job.id, Sequence: action_run_job_id_seq, MAX(id)=22946, last_value=1
WARNING:  Sequence action_run_job_id_seq is behind table data!
NOTICE:  Table: action_runner.id, Sequence: action_runner_id_seq, MAX(id)=4, last_value=1
WARNING:  Sequence action_runner_id_seq is behind table data!
NOTICE:  Table: action_schedule.id, Sequence: action_schedule_id_seq, MAX(id)=4181, last_value=1
WARNING:  Sequence action_schedule_id_seq is behind table data!
NOTICE:  Table: action_schedule_spec.id, Sequence: action_schedule_spec_id_seq, MAX(id)=4181, last_value=1
WARNING:  Sequence action_schedule_spec_id_seq is behind table data!
NOTICE:  Table: action_task.id, Sequence: action_task_id_seq, MAX(id)=22290, last_value=1
WARNING:  Sequence action_task_id_seq is behind table data!
NOTICE:  Table: action_task_output.id, Sequence: action_task_output_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: action_task_step.id, Sequence: action_task_step_id_seq, MAX(id)=23614, last_value=1
WARNING:  Sequence action_task_step_id_seq is behind table data!
NOTICE:  Table: action_tasks_version.id, Sequence: action_tasks_version_id_seq, MAX(id)=22, last_value=1
WARNING:  Sequence action_tasks_version_id_seq is behind table data!
NOTICE:  Table: action_variable.id, Sequence: action_variable_id_seq, MAX(id)=1, last_value=1
NOTICE:  Table: task.id, Sequence: task_id_seq, MAX(id)=2, last_value=1
WARNING:  Sequence task_id_seq is behind table data!
NOTICE:  Table: gpg_key.id, Sequence: gpg_key_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: public_key.id, Sequence: public_key_id_seq, MAX(id)=5, last_value=1
WARNING:  Sequence public_key_id_seq is behind table data!
NOTICE:  Table: deploy_key.id, Sequence: deploy_key_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: org_user.id, Sequence: org_user_id_seq, MAX(id)=4, last_value=1
WARNING:  Sequence org_user_id_seq is behind table data!
NOTICE:  Table: team.id, Sequence: team_id_seq, MAX(id)=2, last_value=1
WARNING:  Sequence team_id_seq is behind table data!
NOTICE:  Table: team_user.id, Sequence: team_user_id_seq, MAX(id)=4, last_value=1
WARNING:  Sequence team_user_id_seq is behind table data!
NOTICE:  Table: team_repo.id, Sequence: team_repo_id_seq, MAX(id)=67, last_value=1
WARNING:  Sequence team_repo_id_seq is behind table data!
NOTICE:  Table: team_unit.id, Sequence: team_unit_id_seq, MAX(id)=30, last_value=1
WARNING:  Sequence team_unit_id_seq is behind table data!
NOTICE:  Table: team_invite.id, Sequence: team_invite_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: project_board.id, Sequence: project_board_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: project_issue.id, Sequence: project_issue_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: project.id, Sequence: project_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: pull_auto_merge.id, Sequence: pull_auto_merge_id_seq, MAX(id)=7161, last_value=1
WARNING:  Sequence pull_auto_merge_id_seq is behind table data!
NOTICE:  Table: review_state.id, Sequence: review_state_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: package.id, Sequence: package_id_seq, MAX(id)=15, last_value=1
WARNING:  Sequence package_id_seq is behind table data!
NOTICE:  Table: package_blob.id, Sequence: package_blob_id_seq, MAX(id)=165, last_value=1
WARNING:  Sequence package_blob_id_seq is behind table data!
NOTICE:  Table: package_cleanup_rule.id, Sequence: package_cleanup_rule_id_seq, MAX(id)=2, last_value=1
WARNING:  Sequence package_cleanup_rule_id_seq is behind table data!
NOTICE:  Table: package_file.id, Sequence: package_file_id_seq, MAX(id)=673, last_value=1
WARNING:  Sequence package_file_id_seq is behind table data!
NOTICE:  Table: package_property.id, Sequence: package_property_id_seq, MAX(id)=1213, last_value=1
WARNING:  Sequence package_property_id_seq is behind table data!
NOTICE:  Table: package_version.id, Sequence: package_version_id_seq, MAX(id)=89, last_value=1
WARNING:  Sequence package_version_id_seq is behind table data!
NOTICE:  Table: quota_group_rule_mapping.id, Sequence: quota_group_rule_mapping_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: quota_group_mapping.id, Sequence: quota_group_mapping_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: branch.id, Sequence: branch_id_seq, MAX(id)=3296, last_value=1
WARNING:  Sequence branch_id_seq is behind table data!
NOTICE:  Table: renamed_branch.id, Sequence: renamed_branch_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: commit_status.id, Sequence: commit_status_id_seq, MAX(id)=106132, last_value=1
WARNING:  Sequence commit_status_id_seq is behind table data!
NOTICE:  Table: commit_status_index.id, Sequence: commit_status_index_id_seq, MAX(id)=106114, last_value=1
WARNING:  Sequence commit_status_index_id_seq is behind table data!
NOTICE:  Table: commit_status_summary.id, Sequence: commit_status_summary_id_seq, MAX(id)=9912, last_value=1
WARNING:  Sequence commit_status_summary_id_seq is behind table data!
NOTICE:  Table: lfs_meta_object.id, Sequence: lfs_meta_object_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: lfs_lock.id, Sequence: lfs_lock_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: protected_branch.id, Sequence: protected_branch_id_seq, MAX(id)=19, last_value=1
WARNING:  Sequence protected_branch_id_seq is behind table data!
NOTICE:  Table: protected_tag.id, Sequence: protected_tag_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: issue_assignees.id, Sequence: issue_assignees_id_seq, MAX(id)=536, last_value=1
WARNING:  Sequence issue_assignees_id_seq is behind table data!
NOTICE:  Table: comment.id, Sequence: comment_id_seq, MAX(id)=33425, last_value=1
WARNING:  Sequence comment_id_seq is behind table data!
NOTICE:  Table: issue_content_history.id, Sequence: issue_content_history_id_seq, MAX(id)=12433, last_value=1
WARNING:  Sequence issue_content_history_id_seq is behind table data!
NOTICE:  Table: issue_dependency.id, Sequence: issue_dependency_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: issue.id, Sequence: issue_id_seq, MAX(id)=7877, last_value=1
WARNING:  Sequence issue_id_seq is behind table data!
NOTICE:  Table: issue_user.id, Sequence: issue_user_id_seq, MAX(id)=23525, last_value=1
WARNING:  Sequence issue_user_id_seq is behind table data!
NOTICE:  Table: issue_watch.id, Sequence: issue_watch_id_seq, MAX(id)=2, last_value=1
WARNING:  Sequence issue_watch_id_seq is behind table data!
NOTICE:  Table: label.id, Sequence: label_id_seq, MAX(id)=18, last_value=1
WARNING:  Sequence label_id_seq is behind table data!
NOTICE:  Table: issue_label.id, Sequence: issue_label_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: milestone.id, Sequence: milestone_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: reaction.id, Sequence: reaction_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: review.id, Sequence: review_id_seq, MAX(id)=4, last_value=1
WARNING:  Sequence review_id_seq is behind table data!
NOTICE:  Table: repo_transfer.id, Sequence: repo_transfer_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: action.id, Sequence: action_id_seq, MAX(id)=202797, last_value=1
WARNING:  Sequence action_id_seq is behind table data!
NOTICE:  Table: federated_user_activity.id, Sequence: federated_user_activity_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: notification.id, Sequence: notification_id_seq, MAX(id)=16179, last_value=1
WARNING:  Sequence notification_id_seq is behind table data!
NOTICE:  Table: access_token_resource_repo.id, Sequence: access_token_resource_repo_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: forgejo_auth_token.id, Sequence: forgejo_auth_token_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: collaboration.id, Sequence: collaboration_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: action_runner_token.id, Sequence: action_runner_token_id_seq, MAX(id)=14, last_value=1
WARNING:  Sequence action_runner_token_id_seq is behind table data!
NOTICE:  Table: action_user.id, Sequence: action_user_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: access.id, Sequence: access_id_seq, MAX(id)=455, last_value=1
WARNING:  Sequence access_id_seq is behind table data!
NOTICE:  Table: pull_request.id, Sequence: pull_request_id_seq, MAX(id)=7770, last_value=1
WARNING:  Sequence pull_request_id_seq is behind table data!
NOTICE:  Table: stopwatch.id, Sequence: stopwatch_id_seq, MAX(id)=0, last_value=1
NOTICE:  Table: tracked_time.id, Sequence: tracked_time_id_seq, MAX(id)=0, last_value=1
DO

Query returned successfully in 139 msec.

Ami nekünk ellenőrzésképp fontos, hogy kiszúrta azt is, ami pillanatnyilag nekünk rossz:

NOTICE:  Table: action_run.id, Sequence: action_run_id_seq, MAX(id)=22893, last_value=13
WARNING:  Sequence action_run_id_seq is behind table data!
A javítás

ChatGPT, kéne egy olyan script is, ami korrigálja a szekvenciák értékét.

Tessék:

DO $$
DECLARE
    r RECORD;
    max_id BIGINT;
    seq_last BIGINT;
BEGIN
    FOR r IN
        SELECT
            ns.nspname AS schema_name,
            seq.relname AS sequence_name,
            tab.relname AS table_name,
            col.attname AS column_name
        FROM pg_class seq
        JOIN pg_namespace ns
            ON ns.oid = seq.relnamespace
        JOIN pg_depend dep
            ON dep.objid = seq.oid
        JOIN pg_class tab
            ON dep.refobjid = tab.oid
        JOIN pg_attribute col
            ON col.attrelid = tab.oid
           AND col.attnum = dep.refobjsubid
        WHERE seq.relkind = 'S'
          AND ns.nspname = 'public'
    LOOP

        EXECUTE format(
            'SELECT COALESCE(MAX(%I), 0) FROM %I.%I',
            r.column_name,
            r.schema_name,
            r.table_name
        )
        INTO max_id;

        EXECUTE format(
            'SELECT last_value FROM %I.%I',
            r.schema_name,
            r.sequence_name
        )
        INTO seq_last;

        IF seq_last < max_id THEN

            RAISE WARNING
                'Fixing sequence %: % -> %',
                r.sequence_name,
                seq_last,
                max_id;

            EXECUTE format(
                'SELECT setval(%L, %s, true)',
                r.schema_name || '.' || r.sequence_name,
                max_id
            );

        END IF;

    END LOOP;
END
$$;

Kimenet:

WARNING:  Fixing sequence dbfs_meta_id_seq: 1 -> 22168
WARNING:  Fixing sequence dbfs_data_id_seq: 1 -> 62424
WARNING:  Fixing sequence access_token_id_seq: 1 -> 18
WARNING:  Fixing sequence secret_id_seq: 1 -> 7
WARNING:  Fixing sequence system_setting_id_seq: 1 -> 3
WARNING:  Fixing sequence hook_task_id_seq: 1 -> 50912
WARNING:  Fixing sequence webhook_id_seq: 1 -> 3873
WARNING:  Fixing sequence email_address_id_seq: 1 -> 4
WARNING:  Fixing sequence user_id_seq: 1 -> 5
WARNING:  Fixing sequence language_stat_id_seq: 1 -> 105
WARNING:  Fixing sequence mirror_id_seq: 1 -> 2
WARNING:  Fixing sequence repo_redirect_id_seq: 1 -> 7
WARNING:  Fixing sequence release_id_seq: 1 -> 59
WARNING:  Fixing sequence repository_id_seq: 1 -> 42
WARNING:  Fixing sequence repo_indexer_status_id_seq: 1 -> 39
WARNING:  Fixing sequence repo_unit_id_seq: 1 -> 686
WARNING:  Fixing sequence watch_id_seq: 1 -> 141
WARNING:  Fixing sequence action_artifact_id_seq: 1 -> 2
WARNING:  Fixing sequence action_run_id_seq: 13 -> 22893
WARNING:  Fixing sequence action_run_job_id_seq: 1 -> 22946
WARNING:  Fixing sequence action_runner_id_seq: 1 -> 4
WARNING:  Fixing sequence action_schedule_id_seq: 1 -> 4181
WARNING:  Fixing sequence action_schedule_spec_id_seq: 1 -> 4181
WARNING:  Fixing sequence action_task_id_seq: 1 -> 22290
WARNING:  Fixing sequence action_task_step_id_seq: 1 -> 23614
WARNING:  Fixing sequence action_tasks_version_id_seq: 1 -> 22
WARNING:  Fixing sequence task_id_seq: 1 -> 2
WARNING:  Fixing sequence public_key_id_seq: 1 -> 5
WARNING:  Fixing sequence org_user_id_seq: 1 -> 4
WARNING:  Fixing sequence team_id_seq: 1 -> 2
WARNING:  Fixing sequence team_user_id_seq: 1 -> 4
WARNING:  Fixing sequence team_repo_id_seq: 1 -> 67
WARNING:  Fixing sequence team_unit_id_seq: 1 -> 30
WARNING:  Fixing sequence pull_auto_merge_id_seq: 1 -> 7161
WARNING:  Fixing sequence package_id_seq: 1 -> 15
WARNING:  Fixing sequence package_blob_id_seq: 1 -> 165
WARNING:  Fixing sequence package_cleanup_rule_id_seq: 1 -> 2
WARNING:  Fixing sequence package_file_id_seq: 1 -> 673
WARNING:  Fixing sequence package_property_id_seq: 1 -> 1213
WARNING:  Fixing sequence package_version_id_seq: 1 -> 89
WARNING:  Fixing sequence branch_id_seq: 1 -> 3296
WARNING:  Fixing sequence commit_status_id_seq: 1 -> 106132
WARNING:  Fixing sequence commit_status_index_id_seq: 1 -> 106114
WARNING:  Fixing sequence commit_status_summary_id_seq: 1 -> 9912
WARNING:  Fixing sequence protected_branch_id_seq: 1 -> 19
WARNING:  Fixing sequence issue_assignees_id_seq: 1 -> 536
WARNING:  Fixing sequence comment_id_seq: 1 -> 33425
WARNING:  Fixing sequence issue_content_history_id_seq: 1 -> 12433
WARNING:  Fixing sequence issue_id_seq: 1 -> 7877
WARNING:  Fixing sequence issue_user_id_seq: 1 -> 23525
WARNING:  Fixing sequence issue_watch_id_seq: 1 -> 2
WARNING:  Fixing sequence label_id_seq: 1 -> 18
WARNING:  Fixing sequence review_id_seq: 1 -> 4
WARNING:  Fixing sequence action_id_seq: 1 -> 202797
WARNING:  Fixing sequence notification_id_seq: 1 -> 16179
WARNING:  Fixing sequence action_runner_token_id_seq: 1 -> 14
WARNING:  Fixing sequence access_id_seq: 1 -> 455
WARNING:  Fixing sequence pull_request_id_seq: 1 -> 7770
DO

Query returned successfully in 2 secs 66 msec.

Továbbra is itt van a kedvenc szekvenciánk:

WARNING:  Fixing sequence action_run_id_seq: 13 -> 22893

Most jó lesz!

Forgejo indítás előtt még futtattam egy forgejo doctor check, illetve egy forgejo doctor check --run check-db-consistency parancsot.

Mindkettő szuper zöld, nem lehet baj.

De azért elővigyázatosságból nem vettem ki az SQL kifejezések naplózását.

Forgejo elindult és:

  • Tudok új tokent létrehozni
  • Maguktól és kézzel is elindulnak az actionök
  • Tudok Docker konténert feltölteni
  • Nincs SQL hiba

Minden jó, ha a vége jó.

u.i.: az eredeti kényelmetlenség, a lassú lekérdezés is megoldódott.