-
[OPIK-6190] [BE] feat: implement migration job to split multi-project automation rules (#6798)
发布于
2026-05-22 10:01:09 +00:00 - [OPIK-6190] [BE] feat: implement migration job to split multi-project automation rules
Adds a Quartz recurring job that splits automation rules spanning multiple
projects (via the automation_rule_projects junction table) into per-project
copies so V2's project-first navigation can represent them correctly.Split algorithm: sort valid project IDs lexicographically; the first keeps
the original rule UUID, remaining copies get fresh UUIDv7 IDs. Partial
deletions (some projects gone) split only surviving projects; full deletions
trap the workspace via dedicated skip columns.Includes:
- AutomationRuleProjectMigrationJob (Quartz + distributed lock)
- AutomationRuleProjectMigrationService (split, trap, cache eviction)
- AutomationRuleMigrationDAO (JDBI + StringTemplate SQL)
- Dedicated workspace columns for per-entity migration observability
- Liquibase migration 000073 for the new columns
- 7 integration tests covering split, partial/full deletion, idempotency,
cache eviction, workspace exclusion, and demo rule filtering
Implements OPIK-6190
- fix(migration): address code review findings
- Remove dead findRuleWithEvaluator method from AutomationRuleMigrationDAO
- Remove uncalled countAutomationRuleMigrationSkipped from DAO/service
- Add NO_OP split outcome for race-condition guard to avoid inflating metrics
- Move project validation outside WRITE transaction to avoid holding two connections
- Remove redundant DISTINCT when GROUP BY is present
- fix(migration): address remaining review comments
- Chain whenComplete on evictAsync for async failure observability
- Rename rules.skipped metric to project_associations.skipped (counts
deleted project associations, not rules) - Fix error duration recording: pass startMillis from caller instead of
capturing System.currentTimeMillis() in the catch (was reporting ~0ms) - Add --comment header to Liquibase migration
- fix: move all-deleted rules to Default Project (disabled) instead of trapping workspace
Address PR review comments and implement Product decision: when all projects
for a rule are deleted, reassign the rule to the Default Project and disable it.
This avoids trapping the workspace, preserves the rule data, and prevents
unintended execution since the rule was for deleted projects anyway.Also addresses remaining review feedback: dedicated scheduler, verbose logging,
DAO cleanup, empty-set handling, RowMapper removal, config-test params, test
splitting, and new test scenarios.- fix(migration): tune config defaults, push LIMIT to SQL, fix double-counting metric
- Reduce maxRulesPerCycle default 100→20 and schedulerThreadCap 4→2
- Push LIMIT into findMultiProjectRuleIds SQL instead of Java subList
- Remove duplicate rulesMovedToDefault.add() in migrateWorkspace()
- Move @NonNull from evictCache interface to implementation only
- fix(migration): re-check junction count inside WRITE tx to close race window
Move the multi-project guard inside the WRITE transaction for both
splitRule and moveRuleToDefaultProject. If a second replica re-enters
after lock expiry, the fresh read serialized by MySQL prevents
duplicate rule creation.- fix(migration): address Andres review — restore prompt config comments, bump maxRulesPerCycle, move sort to SQL
- Restore promptProjectMigration header and inline comments in config.yml
and config-test.yml that were accidentally stripped during rebase conflict
resolution. - Bump maxRulesPerCycle default from 20 to 100 (prod and test) — MySQL
handles the load easily. - Move project_id ordering from service-side .sorted() into the DAO query
(ORDER BY project_id) for predictability; filter freshJunctions by
validProjectIds inside the WRITE tx.
下载附件