1919
2020import java .util .Iterator ;
2121import java .util .concurrent .Callable ;
22+ import java .util .concurrent .CancellationException ;
2223import java .util .concurrent .ConcurrentHashMap ;
24+ import java .util .concurrent .ExecutionException ;
2325import java .util .concurrent .ExecutorService ;
2426import java .util .concurrent .Executors ;
2527import java .util .concurrent .Future ;
@@ -118,6 +120,11 @@ private static boolean sleep(long ms) {
118120 public void cronSchedule () {
119121 // Perform periodic scheduling tasks
120122
123+ // Check closed flag first to exit early
124+ if (this .closed .get ()) {
125+ return ;
126+ }
127+
121128 if (!this .graph .started () || this .graph .closed ()) {
122129 return ;
123130 }
@@ -253,6 +260,10 @@ public <V> Future<?> schedule(HugeTask<V> task) {
253260 return this .ephemeralTaskExecutor .submit (task );
254261 }
255262
263+ // Validate task state before saving to ensure correct exception type
264+ E .checkState (task .type () != null , "Task type can't be null" );
265+ E .checkState (task .name () != null , "Task name can't be null" );
266+
256267 // Process schema task
257268 // Handle gremlin task
258269 // Handle OLAP calculation tasks
@@ -286,13 +297,25 @@ protected <V> void initTaskParams(HugeTask<V> task) {
286297
287298 @ Override
288299 public <V > void cancel (HugeTask <V > task ) {
289- // Update status to CANCELLING
290- if (!task .completed ()) {
291- // Task not completed, can only execute status not CANCELLING
292- this .updateStatus (task .id (), null , TaskStatus .CANCELLING );
293- } else {
294- LOG .info ("cancel task({}) error, task has completed" , task .id ());
300+ E .checkArgumentNotNull (task , "Task can't be null" );
301+
302+ if (task .completed () || task .cancelling ()) {
303+ return ;
295304 }
305+
306+ LOG .info ("Cancel task '{}' in status {}" , task .id (), task .status ());
307+
308+ // Check if task is running locally, cancel it directly if so
309+ HugeTask <?> runningTask = this .runningTasks .get (task .id ());
310+ if (runningTask != null ) {
311+ boolean cancelled = runningTask .cancel (true );
312+ LOG .info ("Cancel local running task '{}' result: {}" , task .id (), cancelled );
313+ return ;
314+ }
315+
316+ // Task not running locally, update status to CANCELLING
317+ // for cronSchedule() or other nodes to handle
318+ this .updateStatus (task .id (), null , TaskStatus .CANCELLING );
296319 }
297320
298321 @ Override
@@ -316,14 +339,25 @@ protected <V> HugeTask<V> deleteFromDB(Id id) {
316339
317340 @ Override
318341 public <V > HugeTask <V > delete (Id id , boolean force ) {
319- if (!force ) {
320- // Change status to DELETING, perform the deletion operation through automatic
321- // scheduling.
322- this .updateStatus (id , null , TaskStatus .DELETING );
342+ HugeTask <?> task = this .taskWithoutResult (id );
343+ if (task == null ) {
323344 return null ;
324- } else {
325- return this .deleteFromDB (id );
326345 }
346+
347+ if (!force ) {
348+ // Check task status: can't delete running tasks without force
349+ if (!task .completed () && task .status () != TaskStatus .DELETING ) {
350+ throw new IllegalArgumentException (
351+ String .format ("Can't delete incomplete task '%s' in status %s, " +
352+ "Please try to cancel the task first" ,
353+ id , task .status ()));
354+ }
355+ // Already in DELETING status, delete directly from DB
356+ // Completed tasks can also be deleted directly
357+ }
358+
359+ // Delete from DB directly for completed/DELETING tasks or force=true
360+ return this .deleteFromDB (id );
327361 }
328362
329363 @ Override
@@ -353,6 +387,18 @@ public boolean close() {
353387 cronFuture .cancel (false );
354388 }
355389
390+ // Wait for cron task to complete to ensure all transactions are closed
391+ try {
392+ cronFuture .get (schedulePeriod + 5 , TimeUnit .SECONDS );
393+ } catch (CancellationException e ) {
394+ // Task was cancelled, this is expected
395+ LOG .debug ("Cron task was cancelled" );
396+ } catch (TimeoutException e ) {
397+ LOG .warn ("Cron task did not complete in time when closing scheduler" );
398+ } catch (ExecutionException | InterruptedException e ) {
399+ LOG .warn ("Exception while waiting for cron task to complete" , e );
400+ }
401+
356402 if (!this .taskDbExecutor .isShutdown ()) {
357403 this .call (() -> {
358404 try {
@@ -363,7 +409,10 @@ public boolean close() {
363409 this .graph .closeTx ();
364410 });
365411 }
366- return true ;
412+
413+ //todo: serverInfoManager section should be removed in the future.
414+ return this .serverManager ().close ();
415+ //return true;
367416 }
368417
369418 @ Override
@@ -387,15 +436,17 @@ private <V> HugeTask<V> waitUntilTaskCompleted(Id id, long seconds,
387436 long passes = seconds * 1000 / intervalMs ;
388437 HugeTask <V > task = null ;
389438 for (long pass = 0 ; ; pass ++) {
390- try {
391- task = this .taskWithoutResult (id );
392- } catch (NotFoundException e ) {
393- if (task != null && task .completed ()) {
394- assert task .id ().asLong () < 0L : task .id ();
439+ HugeTask <V > previousTask = task ;
440+ task = this .taskWithoutResult (id );
441+ if (task == null ) {
442+ // Task not found in DB
443+ if (previousTask != null && previousTask .completed ()) {
444+ // Task was completed and then deleted (ephemeral task case)
445+ assert previousTask .id ().asLong () < 0L : previousTask .id ();
395446 sleep (intervalMs );
396- return task ;
447+ return previousTask ;
397448 }
398- throw e ;
449+ throw new NotFoundException ( "Can't find task with id '%s'" , id ) ;
399450 }
400451 if (task .completed ()) {
401452 // Wait for task result being set after status is completed
@@ -466,6 +517,11 @@ private <V> V call(Callable<V> callable, ExecutorService executor) {
466517 protected boolean updateStatus (Id id , TaskStatus prestatus ,
467518 TaskStatus status ) {
468519 HugeTask <Object > task = this .taskWithoutResult (id );
520+ if (task == null ) {
521+ // Task was already deleted by cronSchedule or another thread
522+ LOG .info ("Task '{}' not found, may have been deleted" , id );
523+ return false ;
524+ }
469525 initTaskParams (task );
470526 if (prestatus == null || task .status () == prestatus ) {
471527 task .overwriteStatus (status );
0 commit comments