I see the problem. All your workers have the same name because the
worker_name defaults to hostanme:port of the web2py instance,
The API have a way to specify a hostname but the command line function
does not.

There are two simple solutions:
- specify a worker_name using shell arguments
- have the worker pick up a UUID worker_name (this may create
problems)

meanwhile you can start the workers passing different -p <n> and this
will fake different worker_names

python web2py.py -K a0 -p 9001
python web2py.py -K a0 -p 9002
python web2py.py -K a0 -p 9003

this should solve the problems.
Your suggested trunk below should go in trunk but it does not solve
the problem. Only makes it more rare.


On 12 Ago, 18:26, Niphlod <[email protected]> wrote:
> I'm trying some variations but it seems that the culprit is assigning
> and retrieving task_scheduled in the same process.
>
> I don't know dal internals with transactions, locking and commits... a
> hint though (my 2 cents): I added, just to check, a line after 245
>
> ...
> if task:
>     if task.assigned_worker_name != self.worker_name:
>         logging.info('Someone stole my task!')
>         return False
>     logging.info('running task %s' % task.name)
> ...
>
> and it never gets actually printed.
> So it's not a problem of "I assigned a task to me, and before it gets
> executed another one picked that task", at least I think.
>
> Right now it seems working ok only if
>
> def assign_next_task_new(self, group_names=['main']):
>         """
>         find next task that needs to be executed
>         """
>         db = self.db
>         row =
> db(db.task_scheduled.assigned_worker_name==self.worker_name).select(limitby 
> =(0,1)).first()
>         return row
>
> is used as a replacement for assign_next_task.
>
> I don't know if it's viable to run a single "assigner" and several
> workers. In python maybe the "assigner" could fetch the task_scheduled
> in waiting state list (with a sane limitby clause) and split evenly
> the list assigning to alive workers....
>
> http://stackoverflow.com/questions/312443/how-do-you-split-a-list-int...
>
> For sql maniacs a simple script can be run as assigner (works only
> with windowing functions, so check if your database supports it)
>
> for postgres this works like a charm:
>
> update task_scheduled
> set assigned_worker_name = worker.name,
> status='running',
> last_run_time=now()
> from
>         (
>         select ntile((select count(*)::int from worker_heartbeat)) OVER
> (order by id) as t_id, *
>         from task_scheduled
>         WHERE 1 = 1
>         AND status = 'queued'
>         AND ((assigned_worker_name IS NULL) OR (assigned_worker_name = ''))
>         ) sched,
>         (
>         select ntile((select count(*)::int from worker_heartbeat)) OVER
> (order by id) as w_id, name
>         from worker_heartbeat
>         ) worker
> WHERE worker.w_id = sched.t_id
> and sched.id = task_scheduled.id
>
> PS: I noticed another "fixable" aspect.... worker_heartbeat gets
> polluted, it would be ok to eliminate the record when ctrl+c is
> pressed (or process is killed gracefully)

Reply via email to