<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>Hi Johannes,</p>
    <p>just stop the execution in QgsTask::run(), for example using a
      break that stops a loop, and return False instead of True.</p>
    <p>From <a class="moz-txt-link-freetext" href="https://api.qgis.org/api/3.30/classQgsTask.html">https://api.qgis.org/api/3.30/classQgsTask.html</a></p>
    <p><br>
    </p>
    <p>
      <blockquote type="cite">
        <p>Performs the task's operation. </p>
        <p>This method will be called when the task commences (ie via
          calling start() ), and subclasses should implement the
          operation they wish to perform in the background within this
          method.</p>
        <p>A task must return a boolean value to indicate whether the
          task was completed successfully or terminated before
          completion. </p>
        <table class="mlabels">
          <tbody>
            <tr>
              <td class="mlabels-left">
                <table class="memname">
                  <tbody>
                    <tr>
                      <td class="memname">virtual bool QgsTask::run </td>
                      <td>(</td>
                      <td class="paramname"><br>
                      </td>
                      <td>)</td>
                      <td><br>
                      </td>
                    </tr>
                  </tbody>
                </table>
              </td>
              <td class="mlabels-right">
                <span class="mlabels"><span class="mlabel">protected</span><span
                    class="mlabel">pure virtual</span></span> </td>
            </tr>
          </tbody>
        </table>
      </blockquote>
      Greetings, Benjamin<br>
    </p>
    <div class="moz-cite-prefix">Am 02.06.2023 um 14:19 schrieb Johannes
      Kröger (WhereGroup) via QGIS-Developer:<br>
    </div>
    <blockquote type="cite"
      cite="mid:3e177275-e9c7-7efb-ac33-30823c6e243c@wheregroup.com">Hi,
      <br>
      <br>
      <a class="moz-txt-link-freetext" href="https://qgis.org/pyqgis/3.30/core/QgsTask.html">https://qgis.org/pyqgis/3.30/core/QgsTask.html</a> says
      <br>
      <br>
      > Long running tasks should periodically check the isCanceled()
      flag to detect if the task has been canceled via some external
      event. If this flag is True then the task should clean up and
      terminate at the earliest possible convenience.
      <br>
      <br>
      How are we supposed to "terminate" a task properly?
      <br>
      <br>
      If we check for task.isCanceled() (or call task.cancel() ourselves
      for testing) and simply return:
      <br>
      <br>
      - QGIS will still show a notification that the "Task completed"
      (instead of "Task failed")
(<a class="moz-txt-link-freetext" href="https://github.com/qgis/QGIS/blob/d3d0431685883b837caa571ad7282828cfbde65e/src/app/qgisapp.cpp#L15707">https://github.com/qgis/QGIS/blob/d3d0431685883b837caa571ad7282828cfbde65e/src/app/qgisapp.cpp#L15707</a>)<br>
      <br>
      - The taskTerminated signal is not emitted. But the taskCompleted
      signal is emitted.
      <br>
      <br>
      - The task's status is QgsTask.Complete
      <br>
      <br>
      There is no obvious way to "terminate" the task from the Python
      side. We cannot set the task's status attribute to
      QgsTask.Terminated
(<a class="moz-txt-link-freetext" href="https://qgis.org/pyqgis/3.30/core/QgsTask.html#qgis.core.QgsTask.Terminated">https://qgis.org/pyqgis/3.30/core/QgsTask.html#qgis.core.QgsTask.Terminated</a>).<br>
      <br>
      <br>
      If an exception happens in the task then it seems to terminate
      "properly", i.e. its status will be QgsTask.Terminated, the
      taskTerminated signal is emitted and a notification "Task failed"
      is shown. This is the only way I found today to get into this
      state. I have not found this documented and only by accident...
      <br>
      <br>
      <br>
      Example for a QgsTask.fromFuncction(..., flags=QgsTask.CanCancel),
      uncomment one of the final lines:
      <br>
      <br>
      def foo(task):
      <br>
              time.sleep(6)  # must be >=
      minTaskLengthForSystemNotification (5 by default)
      <br>
              #task.cancel(); return  # -> Task complete
      <br>
              #raise Exception("fail plz")  # -> Task failed
      <br>
      <br>
      <br>
      It feels like a bug to me (either task.cancel should directly set
      its status to QgsTask.Terminated or we should have a
      task.setStatus() method) but everything in and around QgsTask is
      fairly opaque and hard to grasp so maybe I am just missing
      something obvious.
      <br>
      <br>
      Cheers, Hannes
      <br>
      <br>
      <br>
      PS: I did not test the example function in a clean environment, in
      my test cases I have code like this as methods of a class.
      <br>
      <br>
    </blockquote>
    <pre class="moz-signature" cols="72">-- 
Dr. Benjamin Jakimow
Earth Observation Lab | Geography Department | Humboldt-Universität zu Berlin

e-mail: <a class="moz-txt-link-abbreviated" href="mailto:benjamin.jakimow@geo.hu-berlin.de">benjamin.jakimow@geo.hu-berlin.de</a>
web:    <a class="moz-txt-link-freetext" href="https://hu-berlin.de/eo-lab">https://hu-berlin.de/eo-lab</a>
phone:  +49 (0) 30 2093 6846
mobile: +49 (0) 157 5656 8477
fax:    +49 (0) 30 2093 6848
mail:   Unter den Linden 6 | 10099 Berlin | Germany
room: 2'211
linkedin: <a class="moz-txt-link-freetext" href="https://www.linkedin.com/in/benjamin-jakimow">https://www.linkedin.com/in/benjamin-jakimow</a>
matrix: @jakimowb:hu-berlin.de</pre>
  </body>
</html>