from gluon.scheduler import Scheduler
scheduler = Scheduler(db,heartbeat=3)python web2py.py -K myapp:upload,myapp:upload,myapp:upload,myapp:upload,myapp:upload,myapp:download,myapp:download,myapp:download,myapp:download,myapp:download,myapp:head_monitorQ
GROUP0="myapp:"$HOSTNAME"_comp_0:compQ"GROUP1="myapp:"$HOSTNAME"_comp_1:compQ"GROUP2="myapp:"$HOSTNAME"_comp_2:compQ"GROUP3="myapp:"$HOSTNAME"_comp_3:compQ"GROUP4="myapp:"$HOSTNAME"_comp_4:compQ"GROUP5="myapp:"$HOSTNAME"_comp_5:compQ"GROUP6="myapp:"$HOSTNAME"_comp_6:compQ"MON="myapp:"$HOSTNAME"_monitorQ"
python web2py.py -K $GROUP0,$GROUP1,$GROUP2,$GROUP3,$GROUP4,$GROUP5,$GROUP6,$MONA QUEUED task is not picked up by a worker, it is first ASSIGNED to a worker that can pick up only the ones ASSIGNED to him. The "assignment" phase is important because:
- the group_name parameter is honored (task queued with the group_name 'foo' gets assigned only to workers that process 'foo' tasks (the group_names column in scheduler_workers))
- DISABLED, KILL and TERMINATE workers are "removed" from the assignment alltogether
- in multiple workers situations the QUEUED tasks are split amongst workers evenly, and workers "know in advance" what tasks they are allowed to execute (the assignment allows the scheduler to set up n "independant" queues for the n ACTIVE workers)
I'm have a few things that need clarification and am also experiencing some odd behavior with the scheduler. I'm using my app's db instance (mysql) for the scheduler.
at the bottom of scheduler.py:from gluon.scheduler import Schedulerscheduler = Scheduler(db,heartbeat=3)I start my workers like this:head node:python web2py.py -K myapp:upload,myapp:upload,myapp:upload,myapp:upload,myapp:upload,myapp:download,myapp:download,myapp:download,myapp:download,myapp:download,myapp:head_monitorQ
5 compute nodes:GROUP0="myapp:"$HOSTNAME"_comp_0:compQ"GROUP1="myapp:"$HOSTNAME"_comp_1:compQ"GROUP2="myapp:"$HOSTNAME"_comp_2:compQ"GROUP3="myapp:"$HOSTNAME"_comp_3:compQ"GROUP4="myapp:"$HOSTNAME"_comp_4:compQ"GROUP5="myapp:"$HOSTNAME"_comp_5:compQ"GROUP6="myapp:"$HOSTNAME"_comp_6:compQ"MON="myapp:"$HOSTNAME"_monitorQ"python web2py.py -K $GROUP0,$GROUP1,$GROUP2,$GROUP3,$GROUP4,$GROUP5,$GROUP6,$MONThe head node has 4 "upload" and 4 "download" processes. Each compute node has 7 "compQ" processes that do the actual work. The hostname based groups are unique so I can remotely manage the workers. The monitorQ's run a task every 30s to provide hw monitoring to my application.
1) I have the need to dynamically enable/disable workers to match available hardware. I was hoping to do this with the disable/resume commands but the behavior isn't what I had hoped (but I think what is intended). I would like to send a command that will stop a worker from getting assigned/picking up jobs until a resume is issued. From the docs and experimenting, it looks like all disable does is simply sleep the worker for a little bit and then it gets right back to work. To get my current desired behavior I issue a terminate command, but then i need to ssh into each compute node and restart workers when i want to scale back up...which works but is less than ideal.Is there any way to "toggle" a worker into a disabled state?
2) A previous post from Niphlod explains the worker assignment:A QUEUED task is not picked up by a worker, it is first ASSIGNED to a worker that can pick up only the ones ASSIGNED to him. The "assignment" phase is important because:
- the group_name parameter is honored (task queued with the group_name 'foo' gets assigned only to workers that process 'foo' tasks (the group_names column in scheduler_workers))
- DISABLED, KILL and TERMINATE workers are "removed" from the assignment alltogether
- in multiple workers situations the QUEUED tasks are split amongst workers evenly, and workers "know in advance" what tasks they are allowed to execute (the assignment allows the scheduler to set up n "independant" queues for the n ACTIVE workers)This is an issue for me, because my tasks do not have a uniform run time. Some jobs can take 4 minutes while some can take 4 hours. I keep getting into situations where a node is sitting there with plenty of idle workers available, but they apparently don't have tasks to pick up. Another node is chugging along with a bunch of backlogged assigned tasks. Also sometimes a single worker on a node is left with all the assigned tasks while the other works are sitting idle.Is there any built-in way to periodically force a reassignment of tasks to deal with this type if situation?
3) I had been using "immediate=True" on all of my tasks. I started to see db deadlock errors occasionally when scheduling jobs using queue_task(). Removing "immediate=True" seemed to fix this problem.Is there any reason why immediate could be causing deadlocks?
mysql is the uttermost/personal top 1 dislike/non-standard behaving backend out there, but we'll manage ^_^
and if by "node" you mean a completely different server, you have 7*5 = 35 additional workers on top of the 11 on the "head". That's quite a number of workers, I hope they are there because you need to process at least 46 tasks in parallel
Howdy....4 minutes to 4 hours!!!! ok, we are flexible but hey, 4 hours isn't a task, it's a nightmare
I don't see why for tasks that take 4 minutes to 4 hours, you should use "immediate".
2014-05-23 13:18:10,544 - web2py.scheduler.XXXXXX#16361 - ERROR - Error cleaning up Traceback (most recent call last):
File "/home/xxxxx/anaconda/lib/python2.7/logging/handlers.py", line 76, in emit
if self.shouldRollover(record):
File "/home/xxxxx/anaconda/lib/python2.7/logging/handlers.py", line 157, in shouldRollover
self.stream.seek(0, 2) #due to non-posix-compliant Windows feature
IOError: [Errno 116] Stale file handle
Logged from file scheduler.py, line 822Thanks for the detailed response! Lot's to cover so here we go......hahamysql is the uttermost/personal top 1 dislike/non-standard behaving backend out there, but we'll manage ^_^Interesting. What do you like more?
and if by "node" you mean a completely different server, you have 7*5 = 35 additional workers on top of the 11 on the "head". That's quite a number of workers, I hope they are there because you need to process at least 46 tasks in parallelSo I am certainly using the scheduler in a way it wasn't intended, but that's part of the fun right? I'm in an interesting situation where I have access to a "cluster" of 5 computers that each have 7 GPUs. There currently isn't a proper task scheduler (e.g. SGE, LSF, slurm, etc.) installed yet...sot it's not really much of a cluster beyond a shared filesystem...but I want to use the system now instead of waiting for everything to get setup. I don't have sudo access....so I thought: hey...in less than a day's work I can set up web2py + the built-in scheduler + the comfort scheduler monitor and be able to run distributed GPU processing with a shiny web2py frontend! That is why I need 7 "compQ" workers per machine (1 per GPU). It is also why I include a unique group name for each worker (hostname_compXX). This lets me issue terminate/disable commands to a group and be able to stop specific workers. I need this to control which GPUs will pick up work, since I can't use all of them all the time.
From your description, it is still my understanding that after ~30 seconds a disabled worker will go back to work.
Howdy....4 minutes to 4 hours!!!! ok, we are flexible but hey, 4 hours isn't a task, it's a nightmareHaha...again...obviously stretching things here, but it is pretty much working which is cool. This more or less makes sense, and I'm definitely seeing the impact of a long running task being the TICKER. When this happens nothing moves out of the queued state for a LONG time. Based on what you've said, forcing a new TICKER should make this go away I think. So i may need a simple script i can run to clear the worker table when i see this happen. This won't re-assign already assigned tasks though, correct? For example I see stuff like this:2 workers: A and B4 tasks: 1,2,3,4 - tasks 1 and 2 take 5 minutes, tasks 3 and 4 take 1 hour.Worker A gets assigned tasks 1 and 2, B gets 3 and 4. Tasks 1 and 2 finish in 10 minutes. Worker A sits idle while worker B runs for 2 hours. Is this a correct understanding how things work, or if I force the ticker to PICK it will actually reassign these tasks to an idle worker?
I don't see why for tasks that take 4 minutes to 4 hours, you should use "immediate".I totally agree. It kind of got copy/paste carried over from other code for a web app where it did make sense to use immediate. I'm not doing it anymore. I did go back an check the output from the workers and i do see some errors. There are some application specific things from my code, but also two others of this flavor:2014-05-23 13:18:10,544 - web2py.scheduler.XXXXXX#16361 - ERROR - Error cleaning upTraceback (most recent call last):
File "/home/xxxxx/anaconda/lib/python2.7/logging/handlers.py", line 76, in emit
if self.shouldRollover(record):
File "/home/xxxxx/anaconda/lib/python2.7/logging/handlers.py", line 157, in shouldRollover
self.stream.seek(0, 2) #due to non-posix-compliant Windows feature
IOError: [Errno 116] Stale file handle
Logged from file scheduler.py, line 822Note: I do have the web2py logging setup, but i'm not using it for anything anymore so i could delete the config file. It looks like all the output from the workers is getting put into the web2py log file. Maybe one worker is causing the log file to roll over while another is trying to write to it?
Finally, looking at my notes I've seen some other weird behavior. I'm not sure this is the place for it to go since this post is ridiculously dense to begin with, so let me know if you want me to repost it somewhere else
- If the ticker is a worker who is running a long task, nothing gets assigned for a very long time (I think until the job completes). I think we've covered this behavior above and it makes sense. Forcing a new ticker should fix it.
- Sometimes I see tasks that complete successfully, but get re-run for some reason (i've only seen it with my long running 3-4 hr tasks). Looking in the comfy monitor, the task has a complete run and i see the output, but it gets scheduled and run again. Since my code does cleanup after the first run, the input data is missing so the second run fails (which is how i noticed this). Not sure why this is happening and may need to try to figure out how to reproduce reliably for debugging.
- I've seen situations where I know a task is running, but things are still listed as assigned. I know this because i can see how many tasks are physically running on the worker nodes and can compare that to what the scheduler is reporting. I would assume tasks i know to be running should equal tasks listed as running.
Thanks again for the help and making all this easy, awesome, and free.