Skip to content

docs(15.9): restore configsync first so a snapshot restore brings the dictionaries back - #542

Merged
marevol merged 1 commit into
mainfrom
fix/index-backup-restore-dictionaries
Sep 23, 2026
Merged

marevol merged 1 commit into
mainfrom
fix/index-backup-restore-dictionaries

Conversation

@marevol

@marevol marevol commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Why

config/admin-index-backup.rst cannot be followed to move Fess onto a new OpenSearch. This has been the case since 15.8. It fails in three ways:

  • "Restoring All Indexes" ("indices": "*") fails outright on a fresh node. The configsync plugin creates its own configsync index at startup, so the restore stops with cannot restore index [configsync] because an open index with same name already exists in the cluster.
  • Restoring fess* instead leaves the cluster red. The search index and fess_suggest_analyzer name dictionary files under OpenSearch's config/dictionary (mappings_path, keywords_path, ...). A snapshot carries those settings but not the files, so 6 shards fail with IOException while reading mappings_path: file not readable.
  • Starting Fess against that cluster, as step 5 says, takes the whole web app down. Failed to initialize Lasta Di (a NullPointerException in SuggestHelper#init) is logged and every request returns 404.

The obvious repair does not work either. Copying the dictionary files onto the new node and running _cluster/reroute?retry_failed=true leaves the cluster red. _cluster/allocation/explain gives the reason: restore_in_progress refuses a shard whose restore failed "until the index is closed or deleted" and restored again.

What changes

The dictionaries are stored in the configsync index, which the plugin writes out to config/dictionary. The restore now runs in that order:

  1. Delete the empty configsync that the plugin created, then restore configsync from the snapshot.
  2. POST _configsync/flush to write the files. It rewrites every stored file that is missing or older on disk.
  3. Restore fess*.
  4. Wait for the cluster to leave red before starting Fess.

Other changes:

  • Index table: a configsync row, plus a warning that a snapshot contains no dictionary files.
  • "Backing Up Specific Indexes": now "fess*,configsync". A fess*-only snapshot cannot bring the dictionaries back.
  • Migration steps: point at the ordered restore and check cluster health before starting Fess.
  • New troubleshooting entry, "Cluster Is Red After Restore": the symptoms, why retry_failed does not help, and the recovery. The recovery is to restore configsync and flush, then close the red indexes and restore them again.

This is done for all seven languages, in the 15.9 tree only.

Verification

I used Docker with ghcr.io/codelibs/fess-opensearch:3.8.0 and a Fess 15.9.0-SNAPSHOT ZIP built from main.

Source. I set up host A with three documents, a new admin user, a web crawl config and day_for_cleanup=7 saved in General. I also added a custom synonym entry through the dictionary admin API. I took a snapshot as the page shows and backed up the config files it lists. Then I stopped A.

Before (the page as it is). Host B had a new OpenSearch sharing the repository and a newly unpacked ZIP with the config files copied in.

step result
restore "indices": "*" cannot restore index [configsync] because an open index with same name already exists
restore fess* 52/58 shards; cluster red, 6 unassigned (fess.<timestamp>, fess_suggest_analyzer), IOException while reading keywords_path: file not readable
start Fess Failed to initialize Lasta Di (NPE in SuggestHelper#init), every request 404
copy the dictionary files, reroute?retry_failed=true still red / 6 unassigned; the restore_in_progress decider refuses

After (the commands extracted from the new ja page and run as written). Each run used a fresh OpenSearch and a fresh Fess on B.

snapshot dictionary files on B cluster Fess
snapshot_1 ("*") 0 → 39 after flush green, 0 unassigned starts, 0 ERROR lines
snapshot_fess_only ("fess*,configsync") 0 → 39 green starts, 0 ERROR lines

In both runs the restored Fess returned the same results as the source for everything checked:

  • document count and a search
  • users, web configs, the 14 scheduler jobs and day_for_cleanup=7
  • the list of 103 dictionaries, with the custom synonym entry both in the admin API and in synonym.txt on disk

The user created before the backup logs in with the same password.

Also verified:

  • The troubleshooting recovery, starting from the red state: restore configsync, flush, retry_failed (still red), then close and restore the two red indexes, after which the cluster is green.
  • The in-place note: after fess*/_close on a running cluster, the same steps restore all 58 shards and the cluster is green.

All seven changed files were parsed with docutils and compared against main:

  • Each gains one section, five code blocks and one warning.
  • Nothing is left unparsed (inline literal, |Fess|).
  • The only new messages are INFO-level "enumerated list start value" notes. They come from numbered steps split by :: blocks, which is the page's existing style.
  • The CJK heading rules are generated from display width.

… dictionaries back

The index backup page could not be followed to move Fess to a new
OpenSearch. Its "restore all indexes" example ("indices": "*") fails on
any fresh node, because the configsync plugin creates its own configsync
index at startup and a restore refuses an open index of the same name.
Restoring fess* instead leaves the cluster red: the search index and
fess_suggest_analyzer name dictionary files under OpenSearch's
config/dictionary, a snapshot carries the settings but not the files,
and the shards fail with "IOException while reading mappings_path: file
not readable". Fess started against that cluster fails to initialize
and answers 404 on every page.

The dictionaries live in the configsync index, which the plugin writes
out to config/dictionary. The restore now brings configsync back first,
writes the files with _configsync/flush, and only then restores fess*,
waiting for the cluster to leave red before Fess is started. The
fess-only backup example includes configsync, and the index table says
why it matters.

A new troubleshooting entry covers a cluster that is already red. Copying
the dictionary files and running _cluster/reroute?retry_failed=true does
not recover it: a shard whose restore failed is not allocated again until
its index is closed or deleted and restored once more. The entry closes
the red indexes and restores them again after the files are back.

All seven languages, 15.9 tree only.
@marevol marevol self-assigned this Sep 23, 2026
@marevol
marevol merged commit 16d3428 into main Sep 23, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant