cron_task.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #!/usr/bin/env python2
  2. import signal
  3. import traceback
  4. from sys import stderr
  5. from datetime import datetime, timedelta
  6. from flask.ext.mail import Message
  7. from flask import url_for
  8. import itsdangerous
  9. from ffdnispdb.crawler import TextValidator
  10. from ffdnispdb.models import ISP
  11. from ffdnispdb import app, db, mail
  12. MAX_RUNTIME=15*60
  13. class Timeout(Exception):
  14. pass
  15. class ScriptTimeout(Exception):
  16. """
  17. Script exceeded its allowed run time
  18. """
  19. strike=1
  20. last_isp=-1
  21. script_begin=datetime.now()
  22. def timeout_handler(signum, frame):
  23. global last_isp, strike
  24. if script_begin < datetime.now()-timedelta(seconds=MAX_RUNTIME):
  25. raise ScriptTimeout
  26. if last_isp == isp.id:
  27. strike += 1
  28. if strike > 2:
  29. signal.alarm(6)
  30. raise Timeout
  31. else:
  32. last_isp = isp.id
  33. strike = 1
  34. signal.alarm(6)
  35. signal.signal(signal.SIGALRM, timeout_handler)
  36. signal.alarm(6)
  37. def gen_reactivate_key(isp):
  38. s=itsdangerous.URLSafeSerializer(app.secret_key,
  39. salt='reactivate')
  40. return s.dumps([
  41. isp.id,
  42. str(isp.last_update_attempt)
  43. ])
  44. def send_warning_email(isp, debug_msg):
  45. msg=Message(u"Problem while updating your ISP's data", sender=('FFDN DB <cron@db.ffdn.org>'))
  46. msg.body = """
  47. Hello,
  48. You are receiving this mail because your ISP, %s, is registered on the FFDN ISP Database.
  49. Our automatic update script could not access or process your ISP's data located at %s.
  50. Automatic updates of your ISP were disabled until you fix the problem.
  51. Here is some debug output to help you locate the issue:
  52. %s
  53. ---
  54. When the issue is resolved, please click on the link below to reactivate automatic updates on your ISP:
  55. %s?key=%s
  56. Thanks,
  57. The FFDN ISP Database team
  58. """.strip()%(isp.complete_name, isp.json_url, debug_msg.strip(),
  59. url_for('reactivate_isp', projectid=isp.id), gen_reactivate_key(isp))
  60. msg.add_recipient(isp.tech_email)
  61. print u' Sending notification email to %s'%(isp.tech_email)
  62. mail.send(msg)
  63. app.config['SERVER_NAME'] = 'db.ffdn.org'
  64. app.app_context().push()
  65. try:
  66. for isp in ISP.query.filter(ISP.is_disabled == False,
  67. ISP.json_url != None,
  68. ISP.next_update < datetime.now(),
  69. ISP.update_error_strike < 3)\
  70. .order_by(ISP.last_update_success):
  71. try:
  72. print u'%s: Attempting to update %s'%(datetime.now(), isp)
  73. print u' last successful update=%s'%(isp.last_update_success)
  74. print u' last update attempt=%s'%(isp.last_update_attempt)
  75. print u' next update was scheduled %s ago'%(datetime.now()-isp.next_update)
  76. print u' strike=%d'%(isp.update_error_strike)
  77. isp.last_update_attempt=datetime.now()
  78. db.session.add(isp)
  79. db.session.commit()
  80. validator=TextValidator()
  81. log=''.join(validator(isp.json_url, isp.cache_info or {}))
  82. if not validator.success: # handle error
  83. isp.update_error_strike += 1
  84. if isp.cache_info:
  85. isp.cache_info = validator.cache_info
  86. isp.next_update = datetime.now()+timedelta(seconds=validator.jdict_max_age)
  87. db.session.add(isp)
  88. db.session.commit()
  89. print u'%s: Error while updating:'%(datetime.now())
  90. if isp.update_error_strike >= 3:
  91. print u' three strikes, you\'re out'
  92. send_warning_email(isp, log)
  93. print log.rstrip()+'\n'
  94. continue
  95. if validator.modified:
  96. isp.json = validator.jdict
  97. isp.cache_info = validator.cache_info
  98. isp.last_update_success = isp.last_update_attempt
  99. isp.update_error_strike = 0
  100. isp.next_update = datetime.now()+timedelta(seconds=validator.jdict_max_age)
  101. db.session.add(isp)
  102. db.session.commit()
  103. print u'%s: Update successful !'%(datetime.now())
  104. print u' next update is scheduled for %s\n'%(isp.next_update)
  105. except Timeout:
  106. print u'%s: Timeout while updating:'%(datetime.now())
  107. isp=ISP.query.get(isp.id)
  108. isp.update_error_strike += 1
  109. db.session.add(isp)
  110. db.session.commit()
  111. if isp.update_error_strike >= 3:
  112. send_warning_email(isp, 'Your ISP took more then 18 seconds to process. '
  113. 'Having problems with your webserver ?')
  114. print u' three strikes, you\'re out'
  115. print traceback.format_exc()
  116. except ScriptTimeout:
  117. pass
  118. except Timeout:
  119. pass