|
23 | 23 |
|
24 | 24 | import logging |
25 | 25 | import os |
| 26 | +import socket |
26 | 27 | import threading |
27 | 28 | import time |
28 | 29 |
|
29 | 30 | from app_logging import configure_logging |
30 | 31 | from taskqueue import new_redis_connection |
31 | 32 | from restart_manager import ( |
32 | 33 | RESTART_CHANNEL, |
| 34 | + WORKER_PRESENCE_PREFIX, |
33 | 35 | restart_supervisor_workers, |
34 | 36 | stop_supervisor_workers, |
35 | 37 | start_supervisor_workers, |
|
38 | 40 | logger = logging.getLogger(__name__) |
39 | 41 | configure_logging() |
40 | 42 |
|
| 43 | +PRESENCE_REFRESH_SECONDS = 15 |
| 44 | + |
| 45 | +PRESENCE_TTL_SECONDS = 60 |
| 46 | + |
| 47 | + |
| 48 | +def presence_key(): |
| 49 | + return f"{WORKER_PRESENCE_PREFIX}{socket.gethostname()}:{os.getpid()}" |
| 50 | + |
| 51 | + |
| 52 | +def announce_presence(redis_conn): |
| 53 | + try: |
| 54 | + redis_conn.set(presence_key(), '1', ex=PRESENCE_TTL_SECONDS) |
| 55 | + except Exception: |
| 56 | + logger.exception('Could not refresh the worker restart-listener presence key') |
| 57 | + |
41 | 58 | try: |
42 | 59 | from plugin.manager import worker_presync |
43 | 60 | except Exception: |
@@ -76,14 +93,22 @@ def main(): |
76 | 93 | pubsub.subscribe(channel) |
77 | 94 | logger.info('Subscribed to restart channel. Waiting for restart messages...') |
78 | 95 |
|
79 | | - for message in pubsub.listen(): |
| 96 | + # get_message with a timeout instead of listen(): the presence key below |
| 97 | + # has to be refreshed on a schedule, and listen() blocks forever between |
| 98 | + # messages. Only a WORKER-role listener registers, because only it acts |
| 99 | + # on a signal - the Flask container subscribes and ignores, which is why |
| 100 | + # counting PUBLISH subscribers could never prove delivery. |
| 101 | + while True: |
| 102 | + service_type = os.environ.get('SERVICE_TYPE', '').lower() |
| 103 | + if service_type == 'worker': |
| 104 | + announce_presence(redis_conn) |
| 105 | + message = pubsub.get_message(timeout=PRESENCE_REFRESH_SECONDS) |
80 | 106 | if not message: |
81 | 107 | continue |
82 | 108 | if message.get('type') != 'message': |
83 | 109 | continue |
84 | 110 | payload = message.get('data') |
85 | 111 | logger.info('Control listener received signal: %s', payload) |
86 | | - service_type = os.environ.get('SERVICE_TYPE', '').lower() |
87 | 112 | if service_type != 'worker': |
88 | 113 | logger.info('Control signal received, but SERVICE_TYPE is not worker; skipping') |
89 | 114 | continue |
|
0 commit comments