One question here re: the comment below.  (although now that I skipped ahead in the code this has become a verification of how thigns work):

Transactions guarantee atomicity but not ordering (if multiple processes).  However, the same process first commits a transaction creating the CourseEmail, then it reads the id from the CourseEmail from the db in a new transaction.  Then it creates the task.  By all reasonable computing models this should be enough to sure the task can find the email.

I think there might be a degenerate case where the worker holds a really old cursor to the db and reuses it in the task, therefore it doesn't see any of the transactions on the app server?  Are database cursors new on task creation?  (I don't think there's a reason to doubt that they would be, but am curious)