57 lines
2.1 KiB
Python
57 lines
2.1 KiB
Python
|
|
"""Optional Redis wake-up channel; database remains authoritative job queue.
|
||
|
|
|
||
|
|
Redis outages degrade to timed polling and never lose durable jobs. A bounded
|
||
|
|
list prevents idle systems accumulating unbounded notification entries.
|
||
|
|
"""
|
||
|
|
import os,socket,ssl,time
|
||
|
|
from urllib.parse import urlparse,unquote
|
||
|
|
|
||
|
|
URL=os.getenv('SITEFORGE_REDIS_URL','')
|
||
|
|
|
||
|
|
def _command(sock,*args):
|
||
|
|
payload=b'*'+str(len(args)).encode()+b'\r\n'
|
||
|
|
for arg in args:
|
||
|
|
val=str(arg).encode()
|
||
|
|
payload+=b'$'+str(len(val)).encode()+b'\r\n'+val+b'\r\n'
|
||
|
|
sock.sendall(payload)
|
||
|
|
buf=sock.makefile('rb')
|
||
|
|
line=buf.readline()
|
||
|
|
if not line:raise OSError('Redis disconnected')
|
||
|
|
if line[:1]==b'-':raise OSError(line[1:].decode(errors='replace'))
|
||
|
|
if line[:1] in (b':',b'+'):return line[1:].strip()
|
||
|
|
if line[:1]==b'$':
|
||
|
|
size=int(line[1:].strip())
|
||
|
|
return buf.read(size+2) if size>=0 else None
|
||
|
|
if line[:1]==b'*':
|
||
|
|
count=int(line[1:].strip())
|
||
|
|
for _ in range(max(count,0)):
|
||
|
|
n=int(buf.readline()[1:].strip());buf.read(n+2)
|
||
|
|
return count
|
||
|
|
raise OSError('Unexpected Redis response')
|
||
|
|
|
||
|
|
def _socket():
|
||
|
|
u=urlparse(URL)
|
||
|
|
if u.scheme not in ('redis','rediss'):raise ValueError('Redis URL requires redis/rediss')
|
||
|
|
s=socket.create_connection((u.hostname,u.port or 6379),timeout=3)
|
||
|
|
s.settimeout(4)
|
||
|
|
if u.scheme=='rediss':s=ssl.create_default_context().wrap_socket(s,server_hostname=u.hostname)
|
||
|
|
if u.password:_command(s,'AUTH',unquote(u.password))
|
||
|
|
if u.path and u.path not in ('','/','/0'):_command(s,'SELECT',int(u.path.strip('/')))
|
||
|
|
return s
|
||
|
|
|
||
|
|
def notify():
|
||
|
|
if not URL:return False
|
||
|
|
try:
|
||
|
|
with _socket() as s:
|
||
|
|
_command(s,'LPUSH','siteforge:build:wakeup',1)
|
||
|
|
_command(s,'LTRIM','siteforge:build:wakeup',0,1023)
|
||
|
|
return True
|
||
|
|
except (OSError,ValueError,TypeError):return False
|
||
|
|
|
||
|
|
def wait(fallback=1.5):
|
||
|
|
if not URL:
|
||
|
|
time.sleep(fallback);return
|
||
|
|
try:
|
||
|
|
with _socket() as s:_command(s,'BRPOP','siteforge:build:wakeup',1)
|
||
|
|
except (OSError,ValueError,TypeError):time.sleep(fallback)
|