Synchronizer: Add consolidated sync report and --fail-on-error flag - #258
Merged
dimas-b merged 3 commits intoJul 27, 2026
Merged
Conversation
Prints a consolidated per-entity-type synchronization report at the end of every run, and adds --fail-on-error to exit non-zero when the report contains failures. Entities that were already in sync (skipped) are now tallied separately in the report so idempotent re-runs don't render an empty report.
dimas-b
approved these changes
Jul 22, 2026
dimas-b
left a comment
There was a problem hiding this comment.
Nice enhancement 👍 Thanks again for your contribution, @saidixith002 !
Just one minor comment.
| throw new IllegalArgumentException("Use recordFailure() to record a failed sync."); | ||
| } | ||
| Map<SyncOutcome, Integer> outcomeCounts = counts.get(type); | ||
| outcomeCounts.put(outcome, outcomeCounts.get(outcome) + 1); |
|
@saidixith002 : please resolve merge conflicts |
The merge of main into this branch incorrectly combined the SynchronizationReport and skipIcebergContent constructor parameter additions from two separately-developed features, leaving a malformed duplicated parameter list that failed to compile. Merge the two parameters into a single correct signature and update all call sites.
Contributor
Author
|
@dimas-b , Resolved all the conflicts. Please merge |
dimas-b
approved these changes
Jul 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
PolarisSynchronizercurrently reports progress purely via interleaved SLF4J log lines (clientLogger.info/.error) scattered across each of its 9 sync methods. For anynon-trivial migration — hundreds of catalogs, namespaces, or tables — this is unreadable: there's no way to tell at a glance what succeeded, what failed, or how many entities
of each type were touched without grepping through thousands of log lines.
This is especially painful for automated usage (CI, cron-based backup/sync jobs), where the only way to detect a partial failure today is to scrape logs for
ERRORlines.There's also no way to fail a script/pipeline based on sync outcome —
sync-polarisalways exits0, even if individual entities failed to sync.Additionally, since the sync is designed to be idempotent (only the diff between source and target is applied), a fully-synced re-run currently logs each skipped entity
individually but never surfaces a summary — so a user re-running the tool sees no output at all and can't easily tell "everything is already in sync" from "something silently
didn't run."
What this changes
sync-polarisnow prints a consolidated synchronization report once, at the end of every run, instead of relying on interleaved logs. It summarizes, per entity type,how many entities were
created,overwritten,removed,skipped(already in sync), andfailed, followed by a list of failures with their identifiers and errormessages:
Entity types with all-zero counts are omitted to keep the report scannable, and the
Failures:section is omitted entirely when there are none.Adds a new
--fail-on-errorflag. By default,sync-polarisstill exits0regardless of individual entity failures (preserving existing behavior: failures are loggedand the run continues to completion). With
--fail-on-error, the command exits non-zero if the report contains any failures. This is deliberately distinct from the existing--halt-on-failure, which stops the run at the first failure —--fail-on-errorlets the run finish synchronizing everything it can, then fails afterward, which isgenerally what you want for a CI/cron job (best-effort sync, but still surface that something needs attention).
Entities that were already in sync are now tallied under
skippedrather than just being logged and forgotten. Without this, an idempotent re-run against an already-syncedtarget prints an empty report with no
===content in between, which reads as ambiguous ("did it even check anything?") rather than reassuring.Implementation
EntityType,SyncOutcome, andSynchronizationReportclasses (api/.../planning/plan/), mirroring the existingSynchronizationPlan/PlannedActionpatternalready used elsewhere in this module rather than introducing a new abstraction style.
PolarisSynchronizertakes aSynchronizationReportcollaborator (constructor injection, same pattern asetagManager) and records an outcome at everycreate/overwrite/remove/skip site across all 9 sync methods.
SyncPolarisCommandconstructs the report, passes it intoPolarisSynchronizer, printsreport.render()via the existing console logger after the run completes, andreturns exit code
1when--fail-on-erroris set andreport.hasFailures().--fail-on-error.Test plan
SynchronizationReportTest:recordSuccess/recordFailuretarget the correct cells,hasFailures()toggles correctly,render()omits all-zero entity types and theempty
Failures:section, multiple failures render correctly, andSKIPPEDis counted and rendered without being treated as a failure./gradlew :polaris-synchronizer-api:test :polaris-synchronizer-cli:testpassescreatedcounts; a second, idempotent run showsskippedcounts instead of an empty report