implementing Workers in a real project is having a number of significant issues. We’ve solved most of them but these remain:
Creating and using a Worker in a new project works ok, even when simply reproducing the basic word counter example. But move the code over to our project and
worker1.jobs = jobsArray
gets flagged with "This item does not exist (in Worker console project)
Gets flagged as “Static reference to instance method: call this on instance of class Worker. (in Worker console project)”
We’ve added Worker1 to the “Project Items to Include” list (along with our other items) and it doesn’t make a difference.
We’ve tried this in multiple versions of Xojo
The exact same code works fine in a simple project, but not in our project…
I’ve been experimenting with workers in the last weeks. I just copied my test code to the main project and everything works fine. How is worker1 defined?
at the root level of the project just like in the examples
Weird thing, typical I guess, I finally posted about it and then I got it working the next few things I tried
It turns out I had to hide the method used to call the worker from the worker (by unchecking console 32/64 for the method) - I also had to hide the code that we use to call that method by using TargetHasGUI
Strangely that doesn’t need to be done in the example. One of many undocumented challenges with workers…
I didn’t have to do that. And yes, workers are strange beasts. Great idea and such a poor execution.
workers are thread in debug mode and only true console app workers in builds.
Just out of curiosity, what kind of project are you trying to add them to?
Desktop Mac and Win, if that’s what you mean
Yes. Just wanted to make sure you weren’t copying into a Console or web project.
I never really understood the
Project Items To Include list.
Can somebody give us (me) a better explanation? It would be nice to see an example in the Xojo Documentation on how to use this list.
I once tried to subclass a worker: It didn’t work well.
I also added a worker to be inside a class. This way I thought I could catch events via a
AddHandler delegate. But, I realized that some properties inside my worker didn’t hold any data I set before. But changing those properties to
Shared Properties solved that problem.
Maybe this helps for people dealing with these Worker issues:
Maybe there are better ways, but this is what my workflow looks like at the moment:
== PROCESSOR CLASSES ==
- Add several classes that will do the actual processing.
I have classes for specific tasks: File Hashing; Waveform Generation; Generate Thumbnails; etc.
Instances of these classes will run inside the
JobRun event of a
Worker, to keep them inside the
- Don’t forget to Unlock Any Plugins at this point.
Since the processes run as separate console apps, plugins are not registered. So, when a processor class starts, re-register classes that are used. MBS in some of my cases.
== JOB INFO ==
- Add a JobInfo
class to the project.
this will hold info about a job to be processed.
- Add various properties, like
FolderItems, arrays, and what not. Also, include an Action property, to know the type of process.
I think that the Action property could even be a Delegate, to be invoked during the the
- Add a computed property, called JobID. Leave the setter empty. In the getter an unique value (
UUID) will be given to this property.
== WORKER ==
Add a worker to the project.
Add a dictionary as a Shared Computed Property to the worker class, called “Jobs”
in the getter of that property I create a new dictionary if that dictionary is
this dictionary will store the JobInfo classes as value, and the key will be the corresponding JobID.
String Array as a shared property in the Worker class, named “Pending”.
This array will store the JobID’s waiting to be processed.
String Array as a shared property, named Running.
This will hold a list of ID’s of jobs that are being currently processed.
Add a Shared Method, that will add the JobInfo class to the Jobs dictionary.
After adding the JobInfo, add it’s ID to the Pending Array.
Finally, create a global instance of the
Worker, with a name like MyWorker. And call MyWorker.Start. This instance could be in a global module or in the
App class, I think
JobRequested event, get the first ID from the Pending array. Return from this event with the JobID. Don’t forget to remove that first entry.
JobRun event the JobData parameter holds the JobID.
Add this to the
Find the JobInfo class in the Jobs dictionary.
Start processing that job, according to the info in that JobInfo class.
To keep the
JobRun event clean, I use a
Select Case statement. Within each
Case block I create an instance of a processing class. For instance, I have a processor for generating a Hash for large files; a processor that generates Audio Waveforms; etc…
After completion, I remove the ID from the running array and I return from the
JobRun event with that JobID.
Via some kind of Notification system (observer interfaces, don’t know what it is called), I let my app know what the state of the process is: Running (progress), Error, Completed, etc.
In debug mode, Xojo will simulate this as a Thread.
But after building, the app should actually fire