I am trying to use the task manager to run a long operation (uploading layer to a GeoServer instance, for the Geoserver Explorer plugin), but I am finding some issues.
Here is the code that I am using:
def _publishLayers(catalog, layers, layersUploaded):
task = PublishLayersTask(catalog, layers)
task.taskCompleted.connect(layersUploaded)
QgsApplication.taskManager().addTask(task)
class PublishLayersTask(QgsTask):
def __init__(self, catalog, layers):
QgsTask.__init__(self, "Publish layers")
self.layers = layers
self.catalog = catalog
self.exception = None
self.errortrace = None
def canCancel(self):
return False
def run(self):
try:
//Upload layers here
return True
except Exception as e:
self.exception = e
self.errortrace = traceback.format_exc()
return False
def finished(self, ok):
if ok:
//show confirmation message
else:
//show error message and log error details
The issues I have are mainly two:
1) After adding the task to the task manager, it doesnt start. I have to add some call that refreshes the UI, such as logging a dummy message to the QGIS log or calling processEvents() to have it started. I have tried in Win and Mac, and in both cases the task is not triggered. Docs say that the task manager will take care of running it when it can, but that never happens, no matter what I do on the QGIS UI.
2) The finished
() method is not always run when the task is finished. The layersUploaded
method that is connected to the taskCompleted
signal is always run when the task is correctly finished, but the finished
method of the task is only called sometimes. That doesn't depend on the success of the task. If it fails, the finished
method is only run sometimes, and I could not find any pattern in it.
Any ideas or suggestions?
Best Answer
QGIS version 3.4.2 If you define a task and add it to the task manager within a function scope, it will cause the task to either not execute properly or, at worst, crash QGIS. Consider the following code.
If you put this in the script editor in QGIS and execute it, it will run just fine. The user can cancel. The exceptions are raised, occasionally. All is well. Now if you replace the last block of the code to be within a function scope, like so:
Now when you run the script you will find that either task1 will appear to run, but the completed() function will never be reached (task2 will NOT run) or QGIS will crash. If you run it twice, QGIS will most surely crash. This will also happen when using the class method, as in OP's code. This is likely a bug and I may link to this answer and report it. A possible workaround would be to take the task creation and execution out of scope, as in my first example, and run it from the script editor.
Update: I have reported this issue to QGIS, however it may not be a bug and just a matter of scope. If you have the following code, in a module named task_example.py, you will find it to work correctly for both the subclassed and fromFunction methods:
You can now, in the python console (or another py file), make the following executions:
Please note that I commented out the parts of the code that cause an exception when the random integer is 42. I was tired of the answer to the ultimate question of life, the universe, and everything throwing exceptions at me.