Repository navigation
[#13777] feat(tms): In-job S0 gates, OccupancyGate, and REST Feature lifecycle - #13841
Conversation
…mend gate Add the Spark-side sample → drift → recommend pipeline for cron and commit-chain types without executing the four maintenance operations. Co-authored-by: Cursor <cursoragent@cursor.com>
… upsert Move package to maintenance.injob, drop FileCountThresholdRecommender from main, rename gate APIs/outcomes, and putMetrics on re-sample. Co-authored-by: Cursor <cursoragent@cursor.com>
Re-sampling the same snapshot is out of scope; keep insertMetrics only. Co-authored-by: Cursor <cursoragent@cursor.com>
…-slot APIs Rebase onto feature/tms-scheduler-13773 and replace JobMetaService insertJob with insertInFlight + bindJobId(created_at fence). Co-authored-by: Cursor <cursoragent@cursor.com>
…eature Wire OccupancyGate over soft-slot claim/reclaim/bind/finish and start/stop the three db-scheduler pools from TableMaintenanceRESTFeature. Co-authored-by: Cursor <cursoragent@cursor.com>
…Claim APIs Add Jersey/server-common deps for TableMaintenanceRESTFeature and update tests to bind via OccupancyClaim after apache#13774 landed on main. Co-authored-by: Cursor <cursoragent@cursor.com>
roryqi
left a comment
There was a problem hiding this comment.
I found two lifecycle/clock-consistency issues that should be addressed before relying on the new TMS scheduling path.
| DataSource dataSource = resolveEntityStoreDataSource(); | ||
| TableMaintenanceSchedulerPools pools = new TableMaintenanceSchedulerPools(); | ||
| pools.start(dataSource, TableMaintenanceConfig.from(config)); | ||
| SCHEDULER_POOLS.set(pools); |
There was a problem hiding this comment.
stopSchedulers() is not wired into the Jersey/Jetty or GravitinoServer.stop() lifecycle. The db-scheduler shutdown hooks only run when the JVM terminates, so stopping a server in the same JVM closes the relational DataSource while these pools remain active. A later configure() also starts another set and overwrites this reference, leaving the old pools unreachable. Please register a container shutdown callback that stops these pools before the entity store closes, and guard repeated configuration.
There was a problem hiding this comment.
Addressed in ef8ec42:
- Registered a Jersey
ApplicationEventListenerthat callsstopSchedulers()onDESTROY_FINISHED(runs during Jetty stop, beforeGravitinoEnvcloses the entity-store DataSource). - Guarded repeated
configure()so we do not overwrite a live pool reference / leak the previous pools.
| * @return true when any open row is a live unbound claim or an active Gravitino job | ||
| */ | ||
| public boolean isInFlight(long tableId, long policyId) { | ||
| return isInFlight(tableId, policyId, System.currentTimeMillis()); |
There was a problem hiding this comment.
created_at is deliberately written and reclaimed using the database clock, but this default path compares it with the local JVM clock. In a multi-node deployment, clock skew can make a fresh claim appear expired or keep an expired claim live too long, so shouldSkip() disagrees with the DAO's DB-clock-based acquire/reclaim decision. Please evaluate unbound-claim TTL in the DAO using the database clock (or otherwise use one shared clock), and cover skew in a test.
There was a problem hiding this comment.
Addressed in ef8ec42:
- Unbound TTL is now evaluated in the DAO via
hasLiveUnboundClaim/selectLiveUnboundByTableAndPolicyagainst the database clock (same timeline as acquire/reclaim). OccupancyGate.isInFlightno longer subtracts JVMnowfromcreated_at.- Added
testExpiredUnboundClaimIsNotInFlightOnDbClockso gate occupancy agrees with DB-clock expiry / reclaim.
…lock unbound TTL Register an ApplicationEventListener so pools stop before the entity store closes, skip duplicate configure, and evaluate live unbound claims in the DAO against the database clock so OccupancyGate agrees with acquire/reclaim under JVM skew. Co-authored-by: Cursor <cursoragent@cursor.com>
…s insert race Allow configure-after-stop to re-register the destroy listener; make recordBeforeSnapshot idempotent for the same S0; treat metrics unique conflicts as first-writer-wins. Co-authored-by: Cursor <cursoragent@cursor.com>
Code Coverage Report
Files
|
What changes were proposed in this pull request?
Combines in-job gates and OccupancyGate / REST Feature work on top of merged #13774 (formerly tracked as #13816, folded into #13777):
In-job gates
maintenance.injob: S0 sample → snapshot-drift → recommend gatesTableMaintenanceInJobSampler/TableMaintenanceInJobPipeline(gateCronJob/gateCommitChainType)InJobRecommender+RecommendDecision(injected in tests; no production placeholder recommender)insertMetrics(first-writer-wins on unique race) and setbefore_snapshot_id(same-S0 retry safe)OccupancyClaim(insertInFlight+bindJobId)OccupancyGate + REST Feature
OccupancyGateover soft-slot occupancy: unbound TTL evaluated on the database clock (hasLiveUnboundClaim); bound rows consultJobMetaServicewith nofinished_atbackfillTableMaintenanceRESTFeaturestarts the three db-scheduler pools when the TMS Jersey extension package is enabled, and stops them on JerseyDESTROY_FINISHED(before entity-storeDataSourceclose); configure-after-stop re-registers the destroy listenerserver-commondependencies for the Feature SPIOccupancyGate(including DB-clock unbound expiry) and Feature destroy listenerOut of scope: Four maintenance type executors, OCC commit-chain, PolicyExpand / Spark submit / IRC listener pipelines.
Why are the changes needed?
In-job S0/drift/recommend gates and control-plane occupancy / Feature lifecycle for Epic #13760.
Fix: #13777
Does this PR introduce any user-facing change?
No public REST resources yet. Enabling the TMS extension package starts in-process scheduler pools via
TableMaintenanceRESTFeature.How was this patch tested?