public void sourceTaskFailed(FragmentInstanceId instanceId, Throwable failure) {
    List<FragmentInstanceFailureListener> listeners;
    synchronized (this) {
      sourceInstanceFailures.putIfAbsent(instanceId, failure);
      listeners = ImmutableList.copyOf(sourceInstanceFailureListeners);
    }
    executor.execute(
        () -> {
          for (FragmentInstanceFailureListener listener : listeners) {
            listener.onTaskFailed(instanceId, failure);
          }
        });
  }
Listener is always notified asynchronously using a dedicated notification thread pool so, care
should be taken to avoid leaking {@code this} when adding a listener in a constructor.
Additionally, it is possible notifications are observed out of order due to the asynchronous
execution.
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceStateMachine.java