> -----Original Message-----
> From: sqlalchemy@googlegroups.com 
> [mailto:sqlalch...@googlegroups.com] On Behalf Of gizli
> Sent: 02 September 2009 04:45
> To: sqlalchemy
> Subject: [sqlalchemy] Curious Problem
> 
> 
> Hi all,
> 
> I just discovered something weird when doing concurrency testing with
> my program. Before writing a simplified test case for it and really
> figuring out whether its a bug with sqlalchemy (I am using 0.5.5), I
> wanted to write the scenario here. Basically I was getting the
> infamous "Set size changed during iteration" error during commit.
> Multiple threads are not accessing the same session (as was in some of
> the posts I have read online). Here's what I am doing:
> 
> There is a task dispatcher that queries the database, gets a list of
> tasks to be done, dispatches them to separate threads. Each thread
> creates its own session using the session_maker and updates the status
> of a task. There are three kinds of objects in question: Task,
> TaskSchedule and TaskResult. There is a one-to-many relation between
> Task and TaskSchedule. There is also a one-to-many relation between
> Task and TaskResult. Pseudo code:
> 
> task_dispatcher:
>    for task_schedule in sess.query(TaskSchedule).filter
> (next_execution_time <= current_time):
>        do_task(task_schedule.task) <-- using relation
>        task_schedule.next_execution_time = some_value
>        sess.commit()
> 
> (in a new thread)
> do_task(task):
>      sess := get_session()
>      sess.add(TaskResult(task.id, task_started))
>      sess.commit()
>      task.perform()
>      sess.merge(TaskResult(task.id, task_finished))
>      sess.commit()
>      sess.close()
> 

I'm no expert on any of this, but there are a couple of aspects of this
that I would imagine could be risky. You are obtaining a 'task' object
in your dispatcher thread (so it is attached to that thread's session),
and then using it in another thread. If "task.perform" does any
ORM-related activity (such as triggering lazy loads), they will be
loaded into the dispatcher thread's session, not the subthread's
session.

Also, if your session has expire_on_commit set (defaults to True when
using sessionmaker), then accessing any property at all of the task will
trigger a load.

I think you should either be expunging your task object from the
original session, or at least merging it into your new session. I think
you could use session.merge(task, dont_load=True) to prevent the merge
from querying the database again.

Hope that helps,

Simon

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to