Repository navigation
Conversation
getOffLineJobStatus dereferenced version.getStatus() after parentStore.getVersion(versionNum), which returns null when a version was deleted while a client is still polling job status for it (e.g. a killed system push whose stranded version was removed). The null deref threw a NullPointerException, so the parent controller returned HTTP 500 for every poll of the job endpoint instead of a valid execution status. Derive the version status null-safely (NOT_CREATED when the version is absent) and use it for the deferred-swap terminal check and the KILLED check, mirroring AbstractStore#getVersionStatus semantics. Added TestVeniceParentHelixAdmin#testDeletedVersionExecutionStatus covering the deleted-version path, which previously NPE'd and now returns a valid aggregated status. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address review feedback: compare the enum with == instead of equals(). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When the parent version was deleted while a client still polls its job status, the job status path now treats it as KILLED instead of NOT_CREATED. A deleted version can never complete, so a non-terminal aggregate status is reported as ERROR. VPJ then fails fast and its kill check stops the data writer, instead of polling until the job timeout. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
updateParentVersionStatusIfTerminal can move the parent version from STARTED to PUSHED or ERROR earlier in the same call, and the target-region deferred-swap block needs that new status to run its terminal handling in the poll that sees the failure. Read the status at each point of use through a helper that maps a deleted version to KILLED, instead of capturing it once before the update. Add a test for a target region push with deferred swap whose target region fails, and cover a deleted version on the deferred-swap path in testDeletedVersionExecutionStatus. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A client can poll the parent job status of a version before the push has created that version in the parent, for example right after it starts the push job. Store#getVersion returns null for that version, the same as for a deleted one, so the previous commit reported its job status as ERROR and the poller failed the push. Tell the two cases apart with the largest used version number, as the old version topic cleanup in VeniceHelixAdmin does. A missing version whose number is not larger than the largest used version number was deleted and is still reported as KILLED. A larger number has not been created yet and is reported as NOT_CREATED, which keeps the job status non-terminal so the poller keeps waiting. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This branch has not been deployed
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.
Problem Statement
When a client polls the parent controller for the job status of a version that was already deleted, the
jobendpoint can return HTTP 500. This happens, for example, when a system store push was killed and its stranded version was removed while a client was still polling it.getOffLineJobStatusgets the version withparentStore.getVersion(versionNum), which returns null once the version is deleted, and then callsversion.getStatus()in the KILLED check and in the deferred swap check. Each poll that reaches either check fails with aNullPointerException.getVersionalso returns null before the push has created the version, so a poll that comes that early fails the same way.Solution
This picks up #3001 by @Amar-C and keeps its two commits, which read the version status null-safely and compare it with
==.The third commit follows @ymuppala's review suggestion on #3001 and treats a deleted version as KILLED instead of NOT_CREATED, since a deleted version can never complete:
SystemStoreRepairTasklogs the repair job as failed and stops polling it, instead of polling until its check timeout.The fourth commit reads the version status where it is used, through a small helper, as
maindoes.updateParentVersionStatusIfTerminalcan move the version from STARTED to ERROR earlier in the same call, and the deferred swap check has to see that change to run its topic truncation in the poll that sees the failure. VPJ stops polling once it gets that terminal status, so a later poll may never come.The fifth commit limits the third commit's change to versions that were deleted. A client can also poll before the parent has created the version, e.g. right after it started the push job. With the third commit such a poll got ERROR, and tests in
TestDeferredVersionSwapandTestDeferredVersionSwapWithSequentialRolloutthat start the push job in a background thread and poll right away failed in this CI run with "Unexpected push failure". A missing version now counts as deleted, and so as KILLED, only when its number is not larger than the store's largest used version number. A larger number is reported as NOT_CREATED, as in #3001, so the job status stays non-terminal and the client keeps polling.VeniceHelixAdmin#truncateOldTopicsuses the same rule to tell an old topic from one whose version is not created yet.Nothing changes while the version exists. For a deleted version, a terminal aggregate status other than COMPLETED is returned unchanged, also on a deferred swap poll that used to fail with HTTP 500, and no topic is truncated for it. A COMPLETED aggregate status for a deleted version still fails in
handleTerminalJobStatuswhen it updates the version status, as before. For a version that the push has not created yet, a non-terminal aggregate status is returned as is, as in #3001.Code changes
Concurrency-Specific Checks
Both reviewer and PR author to verify
synchronized,RWLock) are used where needed. No new shared state.ConcurrentHashMap,CopyOnWriteArrayList). No new collections.How was this PR tested?
TestVeniceParentHelixAdmin#testDeletedVersionExecutionStatus, added in [controller] Avoid NPE in job status when the version was deleted #3001, now expects ERROR for a non-terminal aggregate status, and also covers a terminal one and a deferred swap poll. It fails if a deleted version is mapped back to NOT_CREATED, or if the deferred swap check callsgetStatus()on the null version.TestVeniceParentHelixAdmin#testNotYetCreatedVersionExecutionStatuspolls a version whose number is larger than the largest used version number, in a regular and in a deferred swap poll, and expects NOT_CREATED. It fails if every missing version is treated as KILLED.TestVeniceParentHelixAdmin#testTargetRegionDeferredSwapFailureHandledInSamePollcovers the poll in which a target region fails: the parent version moves to ERROR and the stream reprocessing topic is truncated in that same poll. It fails if the version status is read beforeupdateParentVersionStatusIfTerminal.VeniceParentHelixAdminTest,TestTargetedRegionPushWithNativeReplication#testTargetRegionPushWithDeferredVersionSwapand#testKilledRepushJobVersionStatus,TestIncrementalPush#testIncrementalPushAfterKilledPush, andTestAdminOperationWithPreviousVersion#testKillOfflinePushJob,#testDeleteAllVersionsand#testDeleteOldVersion.TestDeferredVersionSwapandTestDeferredVersionSwapWithSequentialRollout, which failed with the third commit in the CI run above, pass with the fifth.Does this PR introduce any user-facing or breaking changes?