Browse Source

Implement "optional" field for servers.

Optional penalty timeout for unresponsive servers.
Refer to new V2 Wiki pages for Config->Scheduling and Config->Servers.
Closes #223 for trunk.
tags/0.6.0
shypike 16 years ago
parent
commit
0c77dff305
  1. 2
      main/interfaces/Default/templates/config_scheduling.tmpl
  2. 4
      main/interfaces/Default/templates/config_server.tmpl
  3. 2
      main/interfaces/Plush/templates/config_scheduling.tmpl
  4. 10
      main/interfaces/Plush/templates/config_server.tmpl
  5. 2
      main/interfaces/prototype/templates/config_scheduling.tmpl
  6. 10
      main/interfaces/prototype/templates/config_server.tmpl
  7. 2
      main/interfaces/smpl/templates/config_scheduling.tmpl
  8. 10
      main/interfaces/smpl/templates/config_server.tmpl
  9. 43
      main/sabnzbd/downloader.py
  10. 27
      main/sabnzbd/scheduler.py

2
main/interfaces/Default/templates/config_scheduling.tmpl

@ -1,6 +1,6 @@
<!--#set global $topmenu="config"#--> <!--#set global $topmenu="config"#-->
<!--#set global $statpath="../.."#--> <!--#set global $statpath="../.."#-->
<!--#set global $helpsubject="Configure+Scheduling"#--> <!--#set global $helpsubject="Configure+Scheduling+V2"#-->
<!--#include $webdir + "/inc_top.tmpl"#--> <!--#include $webdir + "/inc_top.tmpl"#-->
<!--#set global $submenu="scheduling"#--> <!--#set global $submenu="scheduling"#-->

4
main/interfaces/Default/templates/config_server.tmpl

@ -1,6 +1,6 @@
<!--#set global $topmenu="config"#--> <!--#set global $topmenu="config"#-->
<!--#set global $statpath="../.."#--> <!--#set global $statpath="../.."#-->
<!--#set global $helpsubject="Configure+Servers"#--> <!--#set global $helpsubject="Configure+Servers+V2"#-->
<!--#include $webdir + "/inc_top.tmpl"#--> <!--#include $webdir + "/inc_top.tmpl"#-->
<!--#set global $submenu="servers"#--> <!--#set global $submenu="servers"#-->
@ -23,6 +23,7 @@
<input type="checkbox" name="ssl" value="1" <!--#if int($have_ssl) == 0 then "disabled" else ""#-->>&nbsp;SSL<br/> <input type="checkbox" name="ssl" value="1" <!--#if int($have_ssl) == 0 then "disabled" else ""#-->>&nbsp;SSL<br/>
<!--#end if#--> <!--#end if#-->
<input type="checkbox" name="fillserver" value="1">&nbsp;Backup server<br> <input type="checkbox" name="fillserver" value="1">&nbsp;Backup server<br>
<input type="checkbox" name="optional" value="1">&nbsp;Optional<br>
<input type="checkbox" name="enable" value="1" checked="1">&nbsp;Enable<br> <input type="checkbox" name="enable" value="1" checked="1">&nbsp;Enable<br>
<p><input type="submit" value="Add Server"></p> <p><input type="submit" value="Add Server"></p>
</fieldset> </fieldset>
@ -45,6 +46,7 @@
<input type="checkbox" name="ssl" value="1" <!--#if int($servers[$server]['ssl']) != 0 then "checked=1" else ""#-->/>&nbsp;SSL<br/> <input type="checkbox" name="ssl" value="1" <!--#if int($servers[$server]['ssl']) != 0 then "checked=1" else ""#-->/>&nbsp;SSL<br/>
<!--#end if#--> <!--#end if#-->
<input type="checkbox" name="fillserver" value="1" <!--#if int($servers[$server]['fillserver']) != 0 then "checked=1" else ""#--> />&nbsp;Backup server<br/> <input type="checkbox" name="fillserver" value="1" <!--#if int($servers[$server]['fillserver']) != 0 then "checked=1" else ""#--> />&nbsp;Backup server<br/>
<input type="checkbox" name="optional" value="1" <!--#if int($servers[$server]['optional']) != 0 then "checked=1" else ""#--> />&nbsp;Optional<br/>
<input type="checkbox" name="enable" value="1" <!--#if int($servers[$server]['enable']) != 0 then "checked=1" else ""#--> />&nbsp;Enable<br/> <input type="checkbox" name="enable" value="1" <!--#if int($servers[$server]['enable']) != 0 then "checked=1" else ""#--> />&nbsp;Enable<br/>
<input type="hidden" name="server" value="$server"> <input type="hidden" name="server" value="$server">
<p><input type="submit" value="Save Changes"></p> <p><input type="submit" value="Save Changes"></p>

2
main/interfaces/Plush/templates/config_scheduling.tmpl

@ -1,5 +1,5 @@
<!--#set global $pane="Scheduling"#--> <!--#set global $pane="Scheduling"#-->
<!--#set global $help_uri="Configure+Scheduling"#--> <!--#set global $help_uri="Configure+Scheduling+V2"#-->
<!--#include $webdir + "/config_inc_header.tmpl"#--> <!--#include $webdir + "/config_inc_header.tmpl"#-->
<div class="EntryBlock"> <div class="EntryBlock">

10
main/interfaces/Plush/templates/config_server.tmpl

@ -1,5 +1,5 @@
<!--#set global $pane="Servers"#--> <!--#set global $pane="Servers"#-->
<!--#set global $help_uri="Configure+Servers"#--> <!--#set global $help_uri="Configure+Servers+V2"#-->
<!--#include $webdir + "/config_inc_header.tmpl"#--> <!--#include $webdir + "/config_inc_header.tmpl"#-->
<div class="EntryBlock"> <div class="EntryBlock">
@ -37,6 +37,10 @@
<td align="right"><input type="checkbox" name="fillserver" id="fillserver" value="1"/></td> <td align="right"><input type="checkbox" name="fillserver" id="fillserver" value="1"/></td>
<td><label for="fillserver"><strong>Backup&nbsp;Server</strong></label></td> <td><label for="fillserver"><strong>Backup&nbsp;Server</strong></label></td>
</tr> </tr>
<tr>
<td align="right"><input type="checkbox" name="optional" id="optional" value="1"/></td>
<td><label for="optional"><strong>Optional</strong></label></td>
</tr>
<tr><td></td><td><br/><input type="submit" value="Add"/></td></tr> <tr><td></td><td><br/><input type="submit" value="Add"/></td></tr>
@ -87,6 +91,10 @@
<td align="right"><input type="checkbox" name="fillserver" id="fillserver$cur" value="1" <!--#if int($servers[$server]['fillserver']) != 0 then "checked=1" else ""#--> /></td> <td align="right"><input type="checkbox" name="fillserver" id="fillserver$cur" value="1" <!--#if int($servers[$server]['fillserver']) != 0 then "checked=1" else ""#--> /></td>
<td><label for="fillserver$cur"><strong>Backup&nbsp;Server</strong></label></td> <td><label for="fillserver$cur"><strong>Backup&nbsp;Server</strong></label></td>
</tr> </tr>
<tr>
<td align="right"><input type="checkbox" name="optional" id="optional$cur" value="1" <!--#if int($servers[$server]['optional']) != 0 then "checked=1" else ""#--> /></td>
<td><label for="optional$cur"><strong>Optional&nbsp;Server</strong></label></td>
</tr>
<tr><td></td><td> <tr><td></td><td>
<br/><input type="hidden" name="server" value="$server"/> <br/><input type="hidden" name="server" value="$server"/>

2
main/interfaces/prototype/templates/config_scheduling.tmpl

@ -1,5 +1,5 @@
<div id="formPanel"> <div id="formPanel">
<a href="${helpuri}Configure+Scheduling" id="help">Help</a><h3>Scheduling configuration</h3> <a href="${helpuri}Configure+Scheduling+V2" id="help">Help</a><h3>Scheduling configuration</h3>
<br class="clear" /> <br class="clear" />
<div class="EntryBlock"> <div class="EntryBlock">
<form class="cmxform" id="schedule"> <form class="cmxform" id="schedule">

10
main/interfaces/prototype/templates/config_server.tmpl

@ -1,5 +1,5 @@
<div id="formPanel"> <div id="formPanel">
<a href="${helpuri}Configure+Servers" id="help">Help</a><h3>Server configuration</h3> <a href="${helpuri}Configure+Servers+V2" id="help">Help</a><h3>Server configuration</h3>
<div class="EntryBlock"> <div class="EntryBlock">
<br class="clear"/> <br class="clear"/>
<!--#set $slist = $servers.keys()#--> <!--#set $slist = $servers.keys()#-->
@ -32,6 +32,10 @@
<input class="radio" type="checkbox" name="fillserver" value="1" <!--#if int($servers[$server]['fillserver']) != 0 then "checked=1" else ""#--> /></label> <input class="radio" type="checkbox" name="fillserver" value="1" <!--#if int($servers[$server]['fillserver']) != 0 then "checked=1" else ""#--> /></label>
</label><br class="clear" /> </label><br class="clear" />
<label><span class="label">Optional:</span>
<input class="radio" type="checkbox" name="optional" value="1" <!--#if int($servers[$server]['optional']) != 0 then "checked=1" else ""#--> /></label>
</label><br class="clear" />
<label><span class="label">Enable:</span> <label><span class="label">Enable:</span>
<input class="radio" type="checkbox" name="enable" value="1" <!--#if int($servers[$server]['enable']) != 0 then "checked=1" else ""#--> /></label> <input class="radio" type="checkbox" name="enable" value="1" <!--#if int($servers[$server]['enable']) != 0 then "checked=1" else ""#--> /></label>
<input type="hidden" name="server" value="$server"><br class="clear" /> <input type="hidden" name="server" value="$server"><br class="clear" />
@ -78,6 +82,10 @@
<input class="radio" type="checkbox" name="fillserver" value="1"></label> <input class="radio" type="checkbox" name="fillserver" value="1"></label>
<br class="clear" /> <br class="clear" />
<label><span class="label">Optional:</span>
<input class="radio" type="checkbox" name="optional" value="1"></label>
<br class="clear" />
<label><span class="label">Enable:</span> <label><span class="label">Enable:</span>
<input class="radio" type="checkbox" name="enable" value="1"></label> <input class="radio" type="checkbox" name="enable" value="1"></label>
<br class="clear" /> <br class="clear" />

2
main/interfaces/smpl/templates/config_scheduling.tmpl

@ -1,4 +1,4 @@
<a href="${helpuri}Configure+Scheduling" id="help">Help</a><h3>Scheduling configuration</h3> <a href="${helpuri}Configure+Scheduling+V2" id="help">Help</a><h3>Scheduling configuration</h3>
<div class="EntryBlock"> <div class="EntryBlock">
<form class="cmxform" id="schedule"> <form class="cmxform" id="schedule">
<fieldset class="EntryFieldSet"> <fieldset class="EntryFieldSet">

10
main/interfaces/smpl/templates/config_server.tmpl

@ -1,5 +1,5 @@
<a href="${helpuri}Configure+Servers" id="help">Help</a><h3>Server configuration</h3> <a href="${helpuri}Configure+Servers+V2" id="help">Help</a><h3>Server configuration</h3>
<div class="EntryBlock"> <div class="EntryBlock">
<!--#set $slist = $servers.keys()#--> <!--#set $slist = $servers.keys()#-->
<!--#$slist.sort()#--> <!--#$slist.sort()#-->
@ -30,6 +30,10 @@
<input class="radio" type="checkbox" name="fillserver" value="1" <!--#if int($servers[$server]['fillserver']) != 0 then "checked=1" else ""#--> /></label> <input class="radio" type="checkbox" name="fillserver" value="1" <!--#if int($servers[$server]['fillserver']) != 0 then "checked=1" else ""#--> /></label>
</label><br class="clear" /> </label><br class="clear" />
<label><span class="label">Optional:</span>
<input class="radio" type="checkbox" name="optional" value="1" <!--#if int($servers[$server]['optional']) != 0 then "checked=1" else ""#--> /></label>
</label><br class="clear" />
<label><span class="label">Enable:</span> <label><span class="label">Enable:</span>
<input class="radio" type="checkbox" name="enable" value="1" <!--#if int($servers[$server]['enable']) != 0 then "checked=1" else ""#--> /></label> <input class="radio" type="checkbox" name="enable" value="1" <!--#if int($servers[$server]['enable']) != 0 then "checked=1" else ""#--> /></label>
<br class="clear" /> <br class="clear" />
@ -77,6 +81,10 @@
<input class="radio" type="checkbox" name="fillserver" value="1"></label> <input class="radio" type="checkbox" name="fillserver" value="1"></label>
<br class="clear" /> <br class="clear" />
<label><span class="label">Optional:</span>
<input class="radio" type="checkbox" name="optional" value="1"></label>
<br class="clear" />
<label><span class="label">Enable:</span> <label><span class="label">Enable:</span>
<input class="radio" type="checkbox" name="enable" value="1" checked="1"></label> <input class="radio" type="checkbox" name="enable" value="1" checked="1"></label>
<br class="clear" /> <br class="clear" />

43
main/sabnzbd/downloader.py

@ -34,9 +34,17 @@ from sabnzbd.constants import *
import sabnzbd.config as config import sabnzbd.config as config
import sabnzbd.cfg as cfg import sabnzbd.cfg as cfg
import sabnzbd.bpsmeter as bpsmeter import sabnzbd.bpsmeter as bpsmeter
import sabnzbd.scheduler
import sabnzbd.nzbqueue import sabnzbd.nzbqueue
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# Timeout penalty in minutes for each cause
_PENALTY_UNKNOWN = 3
_PENALTY_502 = 5
_PENALTY_TIMEOUT = 10
_PENALTY_SHARE = 15
#------------------------------------------------------------------------------
# Wrapper functions # Wrapper functions
__DOWNLOADER = None # Global pointer to post-proc instance __DOWNLOADER = None # Global pointer to post-proc instance
@ -175,6 +183,7 @@ class Server:
self.busy_threads = [] self.busy_threads = []
self.idle_threads = [] self.idle_threads = []
self.active = True self.active = True
self.bad_cons = 0
for i in range(threads): for i in range(threads):
self.idle_threads.append(NewsWrapper(self, i+1)) self.idle_threads.append(NewsWrapper(self, i+1))
@ -241,6 +250,7 @@ class Downloader(Thread):
""" Setup or re-setup single server """ Setup or re-setup single server
When oldserver is defined and in use, delay startup. When oldserver is defined and in use, delay startup.
Return True when newserver is primary Return True when newserver is primary
Note that the server names are "host:port" strings!
""" """
primary = False primary = False
@ -342,6 +352,13 @@ class Downloader(Thread):
self.__reset_nw(nw, "", warn=False) self.__reset_nw(nw, "", warn=False)
else: else:
self.__reset_nw(nw, "timed out") self.__reset_nw(nw, "timed out")
server.bad_cons += 1
if server.optional and server.active and (server.bad_cons/server.threads) > 3:
server.bad_cons = 0
server.active = False
self.init_server(server.id, None)
logging.warning('Server %s will be ignored for %s minutes', server.id, _PENALTY_TIMEOUT)
sabnzbd.scheduler.plan_server(self.init_server, [None, server.id], _PENALTY_TIMEOUT)
if server.restart: if server.restart:
if not server.busy_threads: if not server.busy_threads:
@ -519,6 +536,7 @@ class Downloader(Thread):
except NNTPPermanentError, error: except NNTPPermanentError, error:
# Handle login problems # Handle login problems
block = False block = False
penalty = 0
msg = error.response msg = error.response
ecode = msg[:3] ecode = msg[:3]
if ecode in ('481', '482', '381') or (ecode == '502' and clues_login(msg)): if ecode in ('481', '482', '381') or (ecode == '502' and clues_login(msg)):
@ -531,19 +549,26 @@ class Downloader(Thread):
logging.error('Too many connections to server %s:%s', server.host, server.port) logging.error('Too many connections to server %s:%s', server.host, server.port)
self.__reset_nw(nw, None, warn=False, destroy=True) self.__reset_nw(nw, None, warn=False, destroy=True)
server.threads -= 1 server.threads -= 1
elif (ecode == '502') and clues_too_many_ip(msg):
# Account sharing?
logging.info("Probable account sharing")
penalty = _PENALTY_SHARE
elif ecode == '502': elif ecode == '502':
# Cannot connect (other reasons), block this server # Cannot connect (other reasons), block this server
if server.active: if server.active:
logging.error('Cannot connect to server %s:%s [%s]', server.host, server.port, msg) logging.warning('Cannot connect to server %s:%s [%s]', server.host, server.port, msg)
block = True penalty = _PENALTY_502
else: else:
# Unknown error, just keep trying # Unknown error, just keep trying
# In the future we will give this server a penalty timeout
logging.error('Cannot connect to server %s:%s [%s]', server.host, server.port, msg) logging.error('Cannot connect to server %s:%s [%s]', server.host, server.port, msg)
if block: penalty = _PENALTY_UNKNOWN
if block or (penalty and server.optional):
if server.active: if server.active:
server.active = False server.active = False
self.init_server(server, None) self.init_server(server, None)
if penalty and server.optional:
logging.info('Server %s ignored for %s minutes', server.id, penalty)
sabnzbd.scheduler.plan_server(self.init_server, [None, server.id], penalty)
self.__reset_nw(nw, None, warn=False) self.__reset_nw(nw, None, warn=False)
continue continue
except: except:
@ -688,3 +713,13 @@ def clues_too_many(text):
if text.find(clue) >= 0: if text.find(clue) >= 0:
return True return True
return False return False
def clues_too_many_ip(text):
""" Check for any "account sharing" clues in the response code
"""
text = text.lower()
for clue in ('simultaneous ip'):
if text.find(clue) >= 0:
return True
return False

27
main/sabnzbd/scheduler.py

@ -28,7 +28,7 @@ import time
import sabnzbd.utils.kronos as kronos import sabnzbd.utils.kronos as kronos
import sabnzbd.rss as rss import sabnzbd.rss as rss
import sabnzbd.newzbin as newzbin import sabnzbd.newzbin as newzbin
import sabnzbd.downloader as downloader import sabnzbd.downloader
import sabnzbd.misc import sabnzbd.misc
import sabnzbd.config as config import sabnzbd.config as config
import sabnzbd.cfg as cfg import sabnzbd.cfg as cfg
@ -80,7 +80,7 @@ def init():
action = scheduled_resume action = scheduled_resume
arguments = [] arguments = []
elif action_name == 'pause': elif action_name == 'pause':
action = downloader.pause_downloader action = sabnzbd.downloader.pause_downloader
arguments = [] arguments = []
elif action_name == 'shutdown': elif action_name == 'shutdown':
action = sabnzbd.shutdown_program action = sabnzbd.shutdown_program
@ -89,7 +89,7 @@ def init():
action = sabnzbd.restart_program action = sabnzbd.restart_program
arguments = [] arguments = []
elif action_name == 'speedlimit' and arguments != []: elif action_name == 'speedlimit' and arguments != []:
action = downloader.limit_speed action = sabnzbd.downloader.limit_speed
elif action_name == 'enable_server' and arguments != []: elif action_name == 'enable_server' and arguments != []:
action = sabnzbd.enable_server action = sabnzbd.enable_server
elif action_name == 'disable_server' and arguments != []: elif action_name == 'disable_server' and arguments != []:
@ -155,7 +155,7 @@ def restart(force=False):
SCHEDULE_GUARD_FLAG = False SCHEDULE_GUARD_FLAG = False
stop() stop()
analyse(downloader.paused()) analyse(sabnzbd.downloader.paused())
init() init()
start() start()
@ -255,9 +255,9 @@ def analyse(was_paused=False):
logging.warning('Schedule for non-existing server %s', value) logging.warning('Schedule for non-existing server %s', value)
if not was_paused: if not was_paused:
downloader.set_paused(paused) sabnzbd.downloader.set_paused(paused)
if speedlimit: if speedlimit:
downloader.limit_speed(speedlimit) sabnzbd.downloader.limit_speed(speedlimit)
for serv in servers: for serv in servers:
try: try:
config.get_config('servers', serv).enable.set(servers[serv]) config.get_config('servers', serv).enable.set(servers[serv])
@ -276,7 +276,7 @@ def scheduled_resume():
""" """
global __PAUSE_END global __PAUSE_END
if __PAUSE_END == None: if __PAUSE_END == None:
downloader.resume_downloader() sabnzbd.downloader.resume_downloader()
def __oneshot_resume(when): def __oneshot_resume(when):
@ -287,7 +287,7 @@ def __oneshot_resume(when):
if __PAUSE_END != None and (when > __PAUSE_END-5) and (when < __PAUSE_END+55): if __PAUSE_END != None and (when > __PAUSE_END-5) and (when < __PAUSE_END+55):
__PAUSE_END = None __PAUSE_END = None
logging.debug('Resume after pause-interval') logging.debug('Resume after pause-interval')
downloader.resume_downloader() sabnzbd.downloader.resume_downloader()
else: else:
logging.debug('Ignoring cancelled resume') logging.debug('Ignoring cancelled resume')
@ -300,10 +300,10 @@ def plan_resume(interval):
__PAUSE_END = time.time() + (interval * 60) __PAUSE_END = time.time() + (interval * 60)
logging.debug('Schedule resume at %s', __PAUSE_END) logging.debug('Schedule resume at %s', __PAUSE_END)
__SCHED.add_single_task(__oneshot_resume, '', interval*60, kronos.method.sequential, [__PAUSE_END], None) __SCHED.add_single_task(__oneshot_resume, '', interval*60, kronos.method.sequential, [__PAUSE_END], None)
downloader.pause_downloader() sabnzbd.downloader.pause_downloader()
else: else:
__PAUSE_END = None __PAUSE_END = None
downloader.resume_downloader() sabnzbd.downloader.resume_downloader()
def pause_int(): def pause_int():
@ -316,3 +316,10 @@ def pause_int():
min = int(val / 60L) min = int(val / 60L)
sec = int(val - min*60) sec = int(val - min*60)
return "%d:%02d" % (min, sec) return "%d:%02d" % (min, sec)
#------------------------------------------------------------------------------
def plan_server(action, parms, penalty):
""" Plan to re-activate server after "penalty" minutes
"""
__SCHED.add_single_task(action, '', penalty*60, kronos.method.sequential, parms, None)

Loading…
Cancel
Save