Code review comment: I presume this is a synchronous write to ZooKeeper? _If_ it's observed to be a performance issue, it could be useful to consider making progress updates async since this is called in the context of a visitor client worker thread callback.

Code under review:
private void progress(DocumentType type) {
        
        reindexing = database.readReindexing();
        status = reindexing.status().getOrDefault(type,
                                                  Status.ready(clock.instant())
                                                        .running()
                                                        .successful(clock.instant()));
        if (ready.get(type).isAfter(status.startedAt()))
            status = Status.ready(clock.instant()); 

        database.writeReindexing(reindexing = reindexing.with(type, status));

        switch (status.state()) {
            default:
                log.log(WARNING, "Unknown reindexing state '" + status.state() + "'");
            case FAILED:
                log.log(FINE, () -> "Not continuing reindexing of " + type + " due to previous failure");
            case SUCCESSFUL: 
                return;
            case RUNNING:
                log.log(WARNING, "Unexpected state 'RUNNING' of reindexing of " + type);
            case READY: 
            log.log(FINE, () -> "Running reindexing of " + type);
        }

        
        status = status.running();
        AtomicReference<Instant> progressLastStored = new AtomicReference<>(clock.instant());
        VisitorControlHandler control = new VisitorControlHandler() {
            @Override
            public void onProgress(ProgressToken token) {
                super.onProgress(token);
                status = status.progressed(token);
                if (progressLastStored.get().isBefore(clock.instant().minusSeconds(10))) {
                    progressLastStored.set(clock.instant());
                    database.writeReindexing(reindexing = reindexing.with(type, status));
                }
            }
            @Override
            public void onDone(CompletionCode code, String message) {
                super.onDone(code, message);
                phaser.arriveAndAwaitAdvance();
            }
        };
        visit(type, status.progress().orElse(null), control);

        
        switch (control.getResult().getCode()) {
            default:
                log.log(WARNING, "Unexpected visitor result '" + control.getResult().getCode() + "'");
            case FAILURE: 
                log.log(WARNING, "Visiting failed: " + control.getResult().getMessage());
                status = status.failed(clock.instant(), control.getResult().getMessage());
                break;
            case ABORTED:
                log.log(FINE, () -> "Halting reindexing of " + type + " due to shutdown — will continue later");
                status = status.halted();
                break;
            case SUCCESS:
                log.log(INFO, "Completed reindexing of " + type + " after " + Duration.between(status.startedAt(), clock.instant()));
                status = status.successful(clock.instant());
        }
        database.writeReindexing(reindexing.with(type, status));
    }

Line commented on: database.writeReindexing(reindexing = reindexing.with(type, status));

Revised code:
private void progress(DocumentType type) {
        
        reindexing = database.readReindexing();
        status = reindexing.status().getOrDefault(type,
                                                  Status.ready(clock.instant())
                                                        .running()
                                                        .successful(clock.instant()));
        if (ready.get(type).isAfter(status.startedAt()))
            status = Status.ready(clock.instant()); 

        database.writeReindexing(reindexing = reindexing.with(type, status));

        switch (status.state()) {
            default:
                log.log(WARNING, "Unknown reindexing state '" + status.state() + "'");
            case FAILED:
                log.log(FINE, () -> "Not continuing reindexing of " + type + " due to previous failure");
            case SUCCESSFUL: 
                return;
            case RUNNING:
                log.log(WARNING, "Unexpected state 'RUNNING' of reindexing of " + type);
            case READY: 
            log.log(FINE, () -> "Running reindexing of " + type);
        }

        
        status = status.running();
        AtomicReference<Instant> progressLastStored = new AtomicReference<>(clock.instant());
        VisitorControlHandler control = new VisitorControlHandler() {
            @Override
            public void onProgress(ProgressToken token) {
                super.onProgress(token);
                status = status.progressed(token);
                if (progressLastStored.get().isBefore(clock.instant().minusSeconds(10))) {
                    progressLastStored.set(clock.instant());
                    database.writeReindexing(reindexing = reindexing.with(type, status));
                }
            }
            @Override
            public void onDone(CompletionCode code, String message) {
                super.onDone(code, message);
                phaser.arriveAndAwaitAdvance(); 
            }
        };
        visit(type, status.progress().orElse(null), control);

        
        switch (control.getResult().getCode()) {
            default:
                log.log(WARNING, "Unexpected visitor result '" + control.getResult().getCode() + "'");
            case FAILURE: 
                log.log(WARNING, "Visiting failed: " + control.getResult().getMessage());
                status = status.failed(clock.instant(), control.getResult().getMessage());
                break;
            case ABORTED:
                log.log(FINE, () -> "Halting reindexing of " + type + " due to shutdown — will continue later");
                status = status.halted();
                break;
            case SUCCESS:
                log.log(INFO, "Completed reindexing of " + type + " after " + Duration.between(status.startedAt(), clock.instant()));
                status = status.successful(clock.instant());
        }
        database.writeReindexing(reindexing.with(type, status));
    }