ok, my responses are inline your post On Friday, June 6, 2014 9:34:00 PM UTC+2, DeanK wrote: > > 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. >
mysql is the uttermost/personal top 1 dislike/non-standard behaving backend out there, but we'll manage ^_^ > > at the bottom of scheduler.py: > > > from gluon.scheduler import Scheduler > > scheduler = 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 upload, 5 download, 1 headmonitorQ. 11 workers > 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,$MON > > > The 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. > 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, otherwise, it's just a waste of processes and groups. Don't know about the sentence "hostname based groups are unique so I can remotely manage the workers" because by default scheduler workers names are "hostname#pid" tagged, so unique by default. On top of that, the default heartbeat of 3 seconds means that even when there are no tasks to process, you have a potential of 46 concurrent processes hitting the database every 3 seconds...is that necessary ? > > 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?* > > funny you say that, I'm actually working on an "autoscaling" management that spawns additional workers (and kills them) when a certain criteria is met to deal with spikes of queued tasks. Let's forget about that for a second, and deal with the current version of the scheduler... there are a few things in your statements that I'd like to "verify"... 1) if you set the status of a worker to "DISABLED", it won't die 2) once DISABLED, it sleeps progressively until 10 times the heartbeat. This means that once set to DISABLED, it progressively waits more seconds to check with the database for a "resume" command, stopping at ~30 seconds. This means that a DISABLED worker, in addition to NOT being able to receive tasks, will only "touch" the db every 30 seconds at most. It's basically doing nothing, and I don't see a reason why you should kill a DISABLED worker because it doesn't consume any resource. It is ready to resume processing and you won't need to ssh into the server to restart the workers processes. > 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?* > > Howdy....4 minutes to 4 hours!!!! ok, we are flexible but hey, 4 hours isn't a task, it's a nightmare. That being said, there's no way that on a short period of time (e.g., 60 seconds) idle workers won't pick up tasks ready to be processed. Long story: only a TICKER process assigns tasks, to avoid concurrency issues, and it assigns tasks roughly every 5 cycles (that is, 15 seconds), unless "immediate" is used when a task gets queued. Consider that as a "meta-task" that only the TICKER does. When a worker is processing a task (i.e. one of the ones that last 4 hours), it's internally marked as "RUNNING" ("instead" of being ACTIVE). When a TICKER is also RUNNING, this means that there could be new tasks ready to be processed, but they won't because the assignment is a "meta-task". There's a specific section of code that deals with this situations and lets the TICKER relinquish its powers to let ACTIVE (not RUNNING) workers pick up the assignment process (lines #944 and following). Finally, to answer your question...if needed you can either: - truncate the workers table (in this case, workers will simply re-insert their record and elect a TICKER) - set the TICKER status to "PICK". This will only force a reassignment in at most 3 seconds vs waiting the usual 15 seconds 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?* > I don't see why for tasks that take 4 minutes to 4 hours, you should use "immediate". Immediate just sets the TICKER status to "PICK" in order to assign task on the next round, instead waiting the usual 5 "loops". This means that immediate can, and should, be used for very (very) fast executing tasks that needs a result within LESS than 15 seconds, that is the WORST scenario that can happen, i.e. the task gets queued the instant after an assignment round happened. Let's get the "general" picture here, because I see many users getting a wrong idea... web2py's scheduler is fast, but it's not meant to process millions of tasks distributed on hundreds of workers (there are far better tools for that job). If you feel the need to use "immediate", it's because you queued a task that needs to return a result fast. Here "fast" means that there is a noticeable change between the time you queue a task and the time you get the result back using "immediate" vs not using it. Given that "immediate" allows to "gain", on average, 8 seconds, in my POV it should only be used with tasks whose execution time is less than 20-30 seconds. For anything higher, you're basically gaining less than the 20%. For less than 20 seconds, if other limitations are not around, you'd better process the task within the webserver, e.g. via ajax, or look at celery (good luck :D) To answer the "deadlock" question, if you see the code, all that "immediate" does is an additional update on the status of the TICKER. This makes a ring bell because - also if "immediate" is not needed in my POV as explained before - points out that your backend can't sustain the db pressure of 46 workers. Do you see any "ERROR" lines in the log of the workers ? -- Resources: - http://web2py.com - http://web2py.com/book (Documentation) - http://github.com/web2py/web2py (Source code) - https://code.google.com/p/web2py/issues/list (Report Issues) --- You received this message because you are subscribed to the Google Groups "web2py-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to web2py+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.