Merge lp:~jcsackett/launchpad/bug-expiration-doesnt-oops into lp:launchpad

Proposed by j.c.sackett
Status: Merged
Approved by: j.c.sackett
Approved revision: no longer in the source branch.
Merged at revision: 12888
Proposed branch: lp:~jcsackett/launchpad/bug-expiration-doesnt-oops
Merge into: lp:launchpad
Diff against target: 27 lines (+10/-4)
1 file modified
cronscripts/expire-bugtasks.py (+10/-4)
To merge this branch: bzr merge lp:~jcsackett/launchpad/bug-expiration-doesnt-oops
Reviewer Review Type Date Requested Status
Robert Collins (community) Approve
Review via email: mp+58412@code.launchpad.net

Commit message

Adds some exception catching and Oops logging to a previously patched problem area in expire-bugtasks.py

Description of the change

Summary
=======
The bug expiration script wasn't working due to a permisions error, but because it wasn't logging the issue no Oops was raised.

The major parts of setting up the script and running the expiration job are now enclosed in try/excepts that log any errors to the Oops handler.

Preimplementation
=================
Spoke with Curtis Hovey

Implementation
==============
Added try/excepts around the initialization of the BugJanitor and the janitor running it's expiration job. The excepts are catchalls because we can't predict what might happen--anything expected should be handled within the routines called, this is a last-ditch "at least log it" measure.

Tests
=====
I cannot for the life of me figure out how to test a cronjob itself. The actual expiration code used by the cronjob is already tested, and the error actually occurs when the cronscript itself is run. If there is a utility to test cronscript/crontabs that I am unaware of, I am happy to implement tests for this.

QA
==
qa-untestable. This will only come into being if we encounter a new error. If necessary, we can alter security.cfg to reintroduce the error we originally discovered and see if it gets logged properly.

Lint
====
= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  cronscripts/expire-bugtasks.py

./cronscripts/expire-bugtasks.py
    16: '_pythonpath' imported but unused
    33: E222 multiple spaces after operator

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote :

So, I'm ok on the testing aspect, but the code needs to be correct :)

try:
   foo = bar
except Exception:
   ..
try:
   foo.quux()
except Exception:
   ..

is going to fail horridly because foo won't be assigned in the second try:except: block.

You can write this correctly as:
try:
    foo = bar
except Exception:
    ..
else:
    try:
       foo.quux()
    except Exception:
       ..

But I think that really all you need is:
try:
   foo = bar
   foo.quux()
except Exception:
   ..
   raise

e.g. (and I've improved the use of logging here too):
+ try:
+ janitor = BugJanitor(
+ log=self.logger, target=target, limit=self.options.limit)
+ janitor.expireBugTasks(self.txn)
+ except Exception:
+ self.logger.error(
+ 'An error occured trying to expire bugtasks.', exc_info=1)
+ raise

The raise is there because we shouldn't swallow exceptions unless we have corrected the error - and we haven't. It may not be needed (I haven't checked to see if that was the last line in the script) but its safer to assume its needed - or put a comment in on why its not, as catchall excepts really are, well, the exception.

review: Needs Fixing
Revision history for this message
Robert Collins (lifeless) wrote :

(by last line, I mean in the context of the whole template-method Script object doohicky, not the code merely in this file :)).

Revision history for this message
j.c.sackett (jcsackett) wrote :

> So, I'm ok on the testing aspect, but the code needs to be correct :)
>
> try:
> foo = bar
> except Exception:
> ..
> try:
> foo.quux()
> except Exception:
> ..
>
> is going to fail horridly because foo won't be assigned in the second
> try:except: block.

Damn, good catch.

Revision history for this message
j.c.sackett (jcsackett) wrote :

> The raise is there because we shouldn't swallow exceptions unless we have
> corrected the error - and we haven't. It may not be needed (I haven't checked
> to see if that was the last line in the script) but its safer to assume its
> needed - or put a comment in on why its not, as catchall excepts really are,
> well, the exception.

You're right about the raise, and I thought I had put that in; it (and the other changes) have been made and pushed up.

Revision history for this message
Robert Collins (lifeless) wrote :

Sweet.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cronscripts/expire-bugtasks.py'
2--- cronscripts/expire-bugtasks.py 2010-10-21 20:05:52 +0000
3+++ cronscripts/expire-bugtasks.py 2011-04-20 14:28:55 +0000
4@@ -47,13 +47,19 @@
5 # Avoid circular import.
6 from lp.registry.interfaces.distribution import IDistributionSet
7 target = getUtility(IDistributionSet).getByName('ubuntu')
8- janitor = BugJanitor(
9- log=self.logger, target=target, limit=self.options.limit)
10- janitor.expireBugTasks(self.txn)
11+ try:
12+ janitor = BugJanitor(
13+ log=self.logger, target=target, limit=self.options.limit)
14+ janitor.expireBugTasks(self.txn)
15+ except Exception:
16+ # We use a catchall here because we don't know (and don't care)
17+ # about the particular error--we'll just log it to as an Oops.
18+ self.logger.error(
19+ 'An error occured trying to expire bugtasks.', exc_info=1)
20+ raise
21
22
23 if __name__ == '__main__':
24 script = ExpireBugTasks(
25 'expire-bugtasks', dbuser=config.malone.expiration_dbuser)
26 script.lock_and_run()
27-