@Override
    public Result reconcile(Request request) {
        return client.fetch(Backup.class, request.name())
            .map(backup -> {
                var metadata = backup.getMetadata();
                var status = backup.getStatus();
                var spec = backup.getSpec();
                if (isDeleted(backup)) {
                    if (removeFinalizers(metadata, Set.of(HOUSE_KEEPER_FINALIZER))) {
                        migrationService.cleanup(backup).block();
                        client.update(backup);
                    }
                    return doNotRetry();
                }
                if (addFinalizers(metadata, Set.of(HOUSE_KEEPER_FINALIZER))) {
                    client.update(backup);
                }

                if (Phase.PENDING.equals(status.getPhase())) {
                    // Do backup
                    try {
                        status.setPhase(Phase.RUNNING);
                        status.setStartTimestamp(Instant.now(clock));
                        updateStatus(request.name(), status);
                        // Long period execution when backing up
                        migrationService.backup(backup).block();
                        status.setPhase(Phase.SUCCEEDED);
                        status.setCompletionTimestamp(Instant.now(clock));
                        updateStatus(request.name(), status);
                    } catch (Throwable t) {
                        var unwrapped = Exceptions.unwrap(t);
                        log.error("Failed to backup", unwrapped);
                        // Only happen when shutting down
                        status.setPhase(Phase.FAILED);
                        if (unwrapped instanceof InterruptedException) {
                            status.setFailureReason("Interrupted");
                            status.setFailureMessage("The backup process was interrupted.");
                        } else {
                            status.setFailureReason("SystemError");
                            status.setFailureMessage(
                                "Something went wrong! Error message: " + unwrapped.getMessage());
                        }
                        updateStatus(request.name(), status);
                    }
                }
                // Only happen when failing to update status when interrupted
                if (Phase.RUNNING.equals(status.getPhase())) {
                    status.setPhase(Phase.FAILED);
                    status.setFailureReason("UnexpectedExit");
                    status.setFailureMessage("The backup process may exit abnormally.");
                    updateStatus(request.name(), status);
                }
                // Check the expires at and requeue if necessary
                if (isTerminal(status.getPhase())) {
                    var expiresAt = spec.getExpiresAt();
                    if (expiresAt != null) {
                        var now = Instant.now(clock);
                        if (now.isBefore(expiresAt)) {
                            return new Result(true, Duration.between(now, expiresAt));
                        }
                        client.delete(backup);
                    }
                }
                return doNotRetry();
            }).orElseGet(Result::doNotRetry);
    }
@Test
    void somethingWentWrongWhenBackup() {
        var name = "fake-backup";
        var backup = createPureBackup(name);
        backup.getSpec().setFormat("zip");
        when(client.fetch(Backup.class, name)).thenReturn(Optional.of(backup));
        doNothing().when(client).update(backup);
        when(migrationService.backup(backup))
            .thenReturn(Mono.error(Exceptions.propagate(new IOException("File not found"))));

        var result = reconciler.reconcile(new Reconciler.Request(name));

        assertNotNull(result);
        assertFalse(result.reEnqueue());

        var status = backup.getStatus();
        assertEquals(Backup.Phase.FAILED, status.getPhase());
        assertNotNull(status.getStartTimestamp());
        assertNull(status.getCompletionTimestamp());
        assertEquals("SystemError", status.getFailureReason());

        // 1. query
        // 2. pending -> running
        // 3. running -> failed
        verify(client, times(3)).fetch(Backup.class, name);
        verify(client, times(3)).update(backup);
        verify(migrationService).backup(backup);
    }