Attached is a diff of the code that I changed in MailManager.py
< = new file
> = old file

The basic idea is that I added a try: except: block in process_task, so that if there is an exception in the code between the getCronLock and releaseCronLock calls, it will drop into the except and then call releaseCronLock.

It's been running for a couple hours without a problem, but our system isn't used heavily.

If folks want to try it, let me know how it goes.

If you would like me to email you the patched file directly, just email me and ask (I didn't want to proliferate a 188K file to all the MM users. That would be naughty).
--
Matthew Caron
Software Developer
InsureMyTrip.com
[EMAIL PROTECTED]

(401) 773-9223
(401) 921-4530 fax


Kevin Campbell wrote:
On Wed, Sep 27, 2006 at 09:18:09AM -0400, Matthew Caron wrote:
The process_task method makes use of get_lock and release_lock under MySQL.
Unfortunately, these are not transaction safe. It is possible that the getmail process failed, aborting the transaction, and leaving the lock open. As Zope does connection pooling with ZMySQLDA, this will hold the lock indefinitely, until that connection is reset.
That might explain why it starts working again when I restart zope.

If you wanted to submit a patch for an alternative locking mechanism for
MySQL 5, that would be appreciated. For now, if you raise a bug on sf it
will be looked at, but I cannot see an immediate fix to this issue.
Why do the locking in the DB in the first place? Assuming that the purpose of the lock is to be sure that two copies of the script don't run, why not just create a lockfile somplace (/var? /tmp? something configurable?) and use it via std. lockfile semantics?

The main reason is that there is no guarantee there is one MailManager instance per database backend, or that they are on the same server.
Alternatively, you can just wrap the body of the script in a big exception handler (assuming Python has such a thing) which starts just after you get the lock and ends just before you release the lock. That way, you can be assured that the lock will get released.

That is certainly an option, and if there was a patch submitted with relevant details and updates to test cases, it should be included in the
core product.

Regards,
Kevin

--
Kevin Campbell Logicalware Ltd
GPG Key: F480EC23

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Mailmanager-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mailmanager-users
1312,1314c1312,1313
<                     try:
<                         log('%sChecking last update for %s' % 
(self.getLogName(), cron_name),
<                              logging.DEBUG, 'cron')
---
>                     log('%sChecking last update for %s' % (self.getLogName(), 
> cron_name),
>                          logging.DEBUG, 'cron')
1316,1332c1315,1325
<                         # Check timestamp. and notify home if past update freq
<                         runupdate = getattr(cronsettings, '%s_due' % 
cron_name)
<                         if runupdate:
<                             log('%sRunning %s' % (self.getLogName(), 
cron_name),
<                                 logging.INFO, 'cron')
<                             ret = method()
<                             self.sql.setCronSettings(
<                                 **{'sqv_%s_setts' % cron_name : self.sql_true}
<                             )                       
<                         else:
<                             log('%s No update due' % (self.getLogName()),
<                                  logging.DEBUG, 'cron')
<             
<                         # Release the lock
<                         self.sql.releaseCronLock(sqv_lock_name = cron_name)
<                     except Exception, e:
<                         log('%sError executing %s - %s' % (self.getLogName(), 
cron_name, e),
---
>                     # Check timestamp. and notify home if past update freq
>                     runupdate = getattr(cronsettings, '%s_due' % cron_name)
>                     if runupdate:
>                         log('%sRunning %s' % (self.getLogName(), cron_name),
>                              logging.INFO, 'cron')
>                         ret = method()
>                         self.sql.setCronSettings(
>                             **{'sqv_%s_setts' % cron_name : self.sql_true}
>                         )                       
>                     else:
>                         log('%s No update due' % (self.getLogName()),
1334c1327,1329
<                         self.sql.releaseCronLock(sqv_lock_name = cron_name)
---
>             
>                     # Release the lock
>                     self.sql.releaseCronLock(sqv_lock_name = cron_name)
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Mailmanager-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mailmanager-users

Reply via email to