mattcasters commented on code in PR #9179:
URL: https://github.com/apache/hop/pull/9179#discussion_r4435555507


##########
engine/src/main/java/org/apache/hop/lineage/hub/LineageHub.java:
##########
@@ -162,25 +168,30 @@ public void flushQuietly() {
     }
   }
 
-  /** Stop the worker thread and shut down sinks. */
+  /**
+   * Stop the worker thread and shut down sinks. Calls are serialized: a 
second call waits until the
+   * first one has delivered the remaining events, instead of shutting the 
sinks down under it.
+   */
   public void shutdown() {
-    running.set(false);
-    Thread t = worker;
-    if (t != null) {
-      t.interrupt();
-      try {
-        t.join(5000);
-      } catch (InterruptedException e) {
-        Thread.currentThread().interrupt();
+    synchronized (shutdownLock) {
+      running.set(false);
+      Thread t = worker;
+      if (t != null) {
+        t.interrupt();
+        try {
+          t.join(5000);
+        } catch (InterruptedException e) {
+          Thread.currentThread().interrupt();
+        }
       }
+      worker = null;

Review Comment:
   **[bug]** `shutdown()` holds `shutdownLock`, but `emit()` / 
`ensureWorkerStarted()` do not. On SIGTERM the JVM starts every shutdown hook 
at once, and `HopEnvironment.shutdown()` calls `LineageHub.shutdown()` 
immediately, while `HopRunShutdownHook` is still stopping the pipeline and only 
shuts the hub down afterwards. The terminal run event is therefore emitted 
during or just after this call.
   
   `running` is already false, so that `emit()` starts a new worker and stores 
it in `worker`. This `worker = null` drops that reference. `drainRemaining()` / 
`shutdownSinks()` can then close the sinks the new worker just installed, and 
if `sinksInitialized` is still false `drainRemaining()` does `queue.clear()`, 
discarding the terminal event and any `FlushRequest` (`flush()` then waits out 
its 60s timeout). The new lock only serializes two `shutdown()` calls. 
`LineageHubConcurrentShutdownTest` never emits while a shutdown is in progress. 
OpenLineage makes the overlap likely: `sink.shutdown()` drains HTTP for up to 
30s on this thread, and the run can finish in that window.
   
   **Suggestion:** Take `shutdownLock` in `ensureWorkerStarted()` so a 
completion event cannot resurrect the hub mid-shutdown. Also gate 
`LineageHub.shutdown()` on the hop-run hook: hold the gate across 
`stopAndWait()` so `HopEnvironment`'s hook blocks until the terminal event is 
queued, then drain once. Add a test that calls `shutdown()` on a slow sink 
while another thread `emit`s, and assert a following `shutdown()` still 
delivers that event.



##########
engine/src/main/java/org/apache/hop/run/HopRunBase.java:
##########
@@ -156,13 +158,24 @@ public abstract class HopRunBase implements Runnable, 
IHasHopMetadataProvider {
               + "this flag is the CLI equivalent of the GUI \"Run anyway\" 
override.")
   protected boolean allowUnsupported = false;
 
+  @CommandLine.Option(
+      names = {"-swt", "--shutdown-timeout"},
+      description =
+          "The maximum number of seconds to wait for the pipeline or workflow 
to stop when hop-run "
+              + "receives a termination signal (SIGTERM, SIGINT, SIGHUP), for 
example from docker "
+              + "stop or Kubernetes. Hop Run stops the run like the Stop 
button in Hop GUI does. "
+              + "Can also be set with the HOP_RUN_SHUTDOWN_TIMEOUT environment 
variable.",
+      defaultValue = "${env:HOP_RUN_SHUTDOWN_TIMEOUT:-25}")

Review Comment:
   **[suggestion]** The default wait is 25 seconds, but the new manual says 
`docker stop` grants 10 seconds (`docker stop --time`) before SIGKILL. The 
timeout is only a maximum, so a run that stops quickly still exits in time, but 
anything slower is killed inside `stopAndWait()` before `afterStop` delivers 
lineage. Kubernetes' default 30s grace does fit; Docker's does not, and the 
docs also ask to leave room for the lineage drain.
   
   **Suggestion:** Default to a value under 10 seconds (and still leave room 
under the Kubernetes grace period for `LineageHub.shutdown()`), or set a 
matching stop grace on the image and say so next to `HOP_RUN_SHUTDOWN_TIMEOUT`.



-- 
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]

Reply via email to