github-actions[bot] commented on code in PR #68007:
URL: https://github.com/apache/doris/pull/68007#discussion_r4014174169


##########
fe/fe-core/src/main/java/org/apache/doris/job/offset/s3/S3SourceOffsetProvider.java:
##########
@@ -168,14 +179,22 @@ public void fetchRemoteMeta(Map<String, String> 
properties) throws Exception {
                 throw new java.io.IOException("debug point: simulated S3 auth 
error");
             }
             GlobListing globListing = 
fileSystem.globListWithLimit(Location.of(filePath), startFile, 1, 1);
-            if (!globListing.getFiles().isEmpty() && 
StringUtils.isNotEmpty(globListing.getMaxFile())) {
+            boolean hasFiles = !globListing.getFiles().isEmpty();
+            if (onceMode && startFile != null && !hasFiles) {

Review Comment:
   [P2] Keep an initially empty ONCE source out of the failure budget
   
   With no committed offset, this branch deliberately leaves reachedEnd false, 
while hasMoreDataToConsume returns true for currentOffset == null. The PENDING 
path does not probe metadata, so a normal empty glob is dispatched; 
getNextOffset throws, the task retries four times, and repeated auto-resumes 
can end in CANNOT_RESUME_ERR. ONCE should either finish an empty snapshot or 
wait through the no-data delay path, but it should not treat zero matches as a 
task failure. Please cover the full PENDING -> scheduler -> task state 
transition, not only the raw provider exception.



##########
fe/fe-core/src/main/java/org/apache/doris/job/offset/SourceOffsetProviderFactory.java:
##########
@@ -35,8 +36,12 @@ public class SourceOffsetProviderFactory {
         map.put("cdc_stream", JdbcTvfSourceOffsetProvider.class);
     }
 
-    public static SourceOffsetProvider createSourceOffsetProvider(String 
sourceType) {
+    public static SourceOffsetProvider createSourceOffsetProvider(
+            String sourceType, StreamingJobProperties jobProperties) {
         try {
+            if ("s3".equalsIgnoreCase(sourceType) && 
jobProperties.isS3OnceMode()) {

Review Comment:
   [P1] Fence ONCE jobs from older FE leaders
   
   The mode is persisted only as a key in the generic properties map. An FE at 
the base version replays that map without validating unknown keys, then its 
one-argument factory always reconstructs the no-arg lexical S3 provider. During 
a rolling FE upgrade, an older follower that becomes leader can therefore turn 
a PENDING ONCE job into indefinite polling and ingest later files instead of 
reaching FINISHED. Please gate creation until every electable FE supports this 
mode, or persist a backward-compatible discriminator that makes old leaders 
fail closed, with a mixed-version replay/failover test.



##########
fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/streaming/StreamingInsertJob.java:
##########
@@ -917,7 +917,7 @@ public void onStreamTaskSuccess(AbstractStreamingTask task) 
throws JobException
             }
 
             
Env.getCurrentEnv().getJobManager().getStreamingTaskManager().removeRunningTask(task);
-            if (offsetProvider.hasReachedEnd()) {
+            if (offsetProvider.hasReachedEnd(task.getRunningOffset())) {

Review Comment:
   [P1] Make ONCE completion terminal across scheduler races
   
   The commit thread holds the job lock through this block, but the recurring 
metadata task performs S3 I/O before acquiring it. If that listing fails while 
the final batch commits, this block sets FINISHED and removes the transaction 
callback; the waiting fetchMeta path then changes the job to PAUSED because 
AbstractJob permits FINISHED -> PAUSED. Auto/manual resume can reopen a job 
whose callback is no longer registered. Both new scheduler completion paths 
have the inverse TOCTOU: their earlier eligibility checks are released before 
an unconditional FINISHED write, so they can overwrite a concurrent 
PAUSED/STOPPED state. Please make these transitions conditional under the same 
job lock, or enforce that terminal states are absorbing, and add latch-based 
coverage.



##########
fe/fe-core/src/main/java/org/apache/doris/job/scheduler/StreamingTaskScheduler.java:
##########
@@ -122,6 +122,11 @@ private void scheduleOneTask(AbstractStreamingTask task) {
         }
         // reject task if no more data to consume
         if (!job.hasMoreDataToConsume()) {
+            if (job.hasReachedEnd()) {

Review Comment:
   [P2] Persist the cloud-replayed offset before finishing
   
   After a crash following a cloud commit, replayOnCloudMode restores the 
authoritative offset only into offsetProvider; unlike local replay, it does not 
refresh offsetProviderPersist. This new exhaustion branch can then journal 
FINISHED with the stale/null persisted string. Because Gson excludes the 
provider object and a restored FINISHED job does not replay Meta Service again, 
a later checkpoint restart permanently shows the old final offset. Please 
synchronize offsetProviderPersist whenever cloud replay applies an attachment 
before allowing either natural-completion path to persist FINISHED, and add a 
cloud recovery plus image-round-trip test.



##########
fe/fe-core/src/main/java/org/apache/doris/job/scheduler/StreamingTaskScheduler.java:
##########
@@ -122,6 +122,11 @@ private void scheduleOneTask(AbstractStreamingTask task) {
         }
         // reject task if no more data to consume
         if (!job.hasMoreDataToConsume()) {
+            if (job.hasReachedEnd()) {
+                job.updateJobStatus(JobStatus.FINISHED);
+                job.logUpdateOperation();
+                return;

Review Comment:
   [P2] Retire the placeholder task when recovery finishes
   
   A recovered ONCE job records a PENDING placeholder task; its first scheduler 
pass delays that task and sets the "will retry" runtime message. After the 
metadata probe marks the source exhausted, the delayed pass reaches this return 
without executing, canceling, finalizing, or removing the task and without 
clearing the message. The job is therefore shown as FINISHED while its task 
remains PENDING with no finish time and the job still says it will retry. 
Please finalize/cancel the placeholder and clear its reference/message as part 
of the terminal transition, with a recovered-empty-tail state test.



##########
fe/fe-core/src/main/java/org/apache/doris/job/extensions/insert/streaming/StreamingJobProperties.java:
##########
@@ -119,6 +124,15 @@ public void validate() throws AnalysisException {
                         && v <= (long) (1024 * 1024 * 1024) * 10,
                 StreamingJobProperties.S3_MAX_BATCH_BYTES_PROPERTY + " should 
between 100MB and 10GB");
 
+        String ingestionMode = getS3IngestionMode();

Review Comment:
   [P2] Reject the S3-only mode on non-S3 sources
   
   This validation runs before the source type is resolved, so cdc_stream and 
FROM-source JDBC jobs accept s3.ingestion_mode=ONCE even though their provider 
paths ignore it and continue indefinitely. The same irrelevant property can 
still reject those providers' supported offset setting here. Please validate 
the explicit property after source/provider resolution in CREATE and ALTER, 
rejecting it outside S3, and add negative coverage for both non-S3 paths.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to