rucio 37.0.0rc3__py3-none-any.whl → 37.0.0rc4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rucio might be problematic. Click here for more details.
- rucio/common/stomp_utils.py +119 -383
- rucio/daemons/cache/consumer.py +90 -26
- rucio/daemons/conveyor/receiver.py +123 -53
- rucio/daemons/hermes/hermes.py +343 -41
- rucio/daemons/tracer/kronos.py +139 -114
- rucio/vcsversion.py +3 -3
- {rucio-37.0.0rc3.dist-info → rucio-37.0.0rc4.dist-info}/METADATA +1 -1
- {rucio-37.0.0rc3.dist-info → rucio-37.0.0rc4.dist-info}/RECORD +67 -67
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/alembic.ini.template +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/alembic_offline.ini.template +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/globus-config.yml.template +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/ldap.cfg.template +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/rucio.cfg.atlas.client.template +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/rucio.cfg.template +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/etc/rucio_multi_vo.cfg.template +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/requirements.server.txt +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/tools/bootstrap.py +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/tools/merge_rucio_configs.py +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/data/rucio/tools/reset_database.py +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-abacus-account +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-abacus-collection-replica +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-abacus-rse +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-admin +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-atropos +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-auditor +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-automatix +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-bb8 +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-cache-client +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-cache-consumer +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-finisher +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-poller +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-preparer +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-receiver +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-stager +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-submitter +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-throttler +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-dark-reaper +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-dumper +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-follower +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-hermes +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-judge-cleaner +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-judge-evaluator +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-judge-injector +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-judge-repairer +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-kronos +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-minos +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-minos-temporary-expiration +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-necromancer +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-oauth-manager +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-reaper +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-replica-recoverer +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-rse-decommissioner +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-storage-consistency-actions +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-transmogrifier +0 -0
- {rucio-37.0.0rc3.data → rucio-37.0.0rc4.data}/scripts/rucio-undertaker +0 -0
- {rucio-37.0.0rc3.dist-info → rucio-37.0.0rc4.dist-info}/WHEEL +0 -0
- {rucio-37.0.0rc3.dist-info → rucio-37.0.0rc4.dist-info}/licenses/AUTHORS.rst +0 -0
- {rucio-37.0.0rc3.dist-info → rucio-37.0.0rc4.dist-info}/licenses/LICENSE +0 -0
- {rucio-37.0.0rc3.dist-info → rucio-37.0.0rc4.dist-info}/top_level.txt +0 -0
rucio/daemons/cache/consumer.py
CHANGED
|
@@ -21,12 +21,13 @@ import logging
|
|
|
21
21
|
import threading
|
|
22
22
|
import time
|
|
23
23
|
from traceback import format_exc
|
|
24
|
-
from typing import TYPE_CHECKING
|
|
24
|
+
from typing import TYPE_CHECKING, Optional
|
|
25
25
|
|
|
26
26
|
import rucio.db.sqla.util
|
|
27
27
|
from rucio.common import exception
|
|
28
|
+
from rucio.common.config import config_get, config_get_bool, config_get_int, config_get_list
|
|
28
29
|
from rucio.common.logging import formatted_logger, setup_logging
|
|
29
|
-
from rucio.common.stomp_utils import
|
|
30
|
+
from rucio.common.stomp_utils import StompConnectionManager
|
|
30
31
|
from rucio.common.types import InternalScope, LoggerFunction
|
|
31
32
|
from rucio.core.monitor import MetricManager
|
|
32
33
|
from rucio.core.rse import get_rse_id
|
|
@@ -35,6 +36,7 @@ from rucio.core.volatile_replica import add_volatile_replicas, delete_volatile_r
|
|
|
35
36
|
if TYPE_CHECKING:
|
|
36
37
|
from types import FrameType
|
|
37
38
|
|
|
39
|
+
from stomp import Connection
|
|
38
40
|
from stomp.utils import Frame
|
|
39
41
|
|
|
40
42
|
logging.getLogger("stomp").setLevel(logging.CRITICAL)
|
|
@@ -44,11 +46,35 @@ GRACEFUL_STOP = threading.Event()
|
|
|
44
46
|
DAEMON_NAME = 'cache-consumer'
|
|
45
47
|
|
|
46
48
|
|
|
47
|
-
class AMQConsumer
|
|
49
|
+
class AMQConsumer:
|
|
48
50
|
"""
|
|
49
51
|
class Consumer
|
|
50
52
|
"""
|
|
51
53
|
|
|
54
|
+
def __init__(
|
|
55
|
+
self,
|
|
56
|
+
broker: str,
|
|
57
|
+
conn: "Connection",
|
|
58
|
+
logger: "LoggerFunction"
|
|
59
|
+
):
|
|
60
|
+
"""
|
|
61
|
+
__init__
|
|
62
|
+
"""
|
|
63
|
+
self.__broker = broker
|
|
64
|
+
self.__conn = conn
|
|
65
|
+
self.__logger = logger
|
|
66
|
+
|
|
67
|
+
@METRICS.count_it
|
|
68
|
+
def on_heartbeat_timeout(self) -> None:
|
|
69
|
+
self.__conn.disconnect()
|
|
70
|
+
|
|
71
|
+
@METRICS.count_it
|
|
72
|
+
def on_error(self, frame: "Frame") -> None:
|
|
73
|
+
"""
|
|
74
|
+
on_error
|
|
75
|
+
"""
|
|
76
|
+
self.__logger(logging.ERROR, 'Message receive error: [%s] %s' % (self.__broker, frame.body))
|
|
77
|
+
|
|
52
78
|
@METRICS.count_it
|
|
53
79
|
def on_message(self, frame: "Frame") -> None:
|
|
54
80
|
"""
|
|
@@ -56,7 +82,7 @@ class AMQConsumer(ListenerBase):
|
|
|
56
82
|
"""
|
|
57
83
|
try:
|
|
58
84
|
msg = json.loads(frame.body) # type: ignore
|
|
59
|
-
self.
|
|
85
|
+
self.__logger(logging.DEBUG, 'Message received: %s ' % msg)
|
|
60
86
|
if isinstance(msg, dict) and 'operation' in msg.keys():
|
|
61
87
|
for f in msg['files']:
|
|
62
88
|
f['scope'] = InternalScope(f['scope'])
|
|
@@ -67,42 +93,81 @@ class AMQConsumer(ListenerBase):
|
|
|
67
93
|
|
|
68
94
|
rse_vo_str = msg['rse']
|
|
69
95
|
if 'vo' in msg and msg['vo'] != 'def':
|
|
70
|
-
rse_vo_str =
|
|
96
|
+
rse_vo_str = '{} on {}'.format(rse_vo_str, msg['vo'])
|
|
71
97
|
if msg['operation'] == 'add_replicas':
|
|
72
|
-
self.
|
|
98
|
+
self.__logger(logging.INFO, 'add_replicas to RSE %s: %s ' % (rse_vo_str, str(msg['files'])))
|
|
73
99
|
add_volatile_replicas(rse_id=rse_id, replicas=msg['files'])
|
|
74
100
|
elif msg['operation'] == 'delete_replicas':
|
|
75
|
-
self.
|
|
101
|
+
self.__logger(logging.INFO, 'delete_replicas to RSE %s: %s ' % (rse_vo_str, str(msg['files'])))
|
|
76
102
|
delete_volatile_replicas(rse_id=rse_id, replicas=msg['files'])
|
|
77
103
|
else:
|
|
78
|
-
self.
|
|
104
|
+
self.__logger(logging.DEBUG, 'Check failed: %s %s '
|
|
105
|
+
% (isinstance(msg, dict), 'operation' in msg.keys()))
|
|
79
106
|
except:
|
|
80
|
-
self.
|
|
107
|
+
self.__logger(logging.ERROR, str(format_exc()))
|
|
81
108
|
|
|
82
109
|
|
|
83
|
-
def consumer(id_: int, num_thread: int = 1
|
|
110
|
+
def consumer(id_: int, num_thread: int = 1) -> None:
|
|
84
111
|
"""
|
|
85
112
|
Main loop to consume messages from the Rucio Cache producer.
|
|
86
113
|
"""
|
|
114
|
+
|
|
115
|
+
logger = formatted_logger(logging.log, DAEMON_NAME + ' %s')
|
|
116
|
+
|
|
87
117
|
logger(logging.INFO, 'Rucio Cache consumer starting')
|
|
88
118
|
|
|
89
|
-
|
|
119
|
+
brokers = config_get_list('messaging-cache', 'brokers')
|
|
120
|
+
|
|
121
|
+
use_ssl = config_get_bool('messaging-cache', 'use_ssl', default=True, raise_exception=False)
|
|
122
|
+
if not use_ssl:
|
|
123
|
+
username = config_get('messaging-cache', 'username')
|
|
124
|
+
password = config_get('messaging-cache', 'password')
|
|
125
|
+
destination = config_get('messaging-cache', 'destination')
|
|
126
|
+
subscription_id = 'rucio-cache-messaging'
|
|
127
|
+
|
|
128
|
+
vhost = config_get('messaging-cache', 'broker_virtual_host', raise_exception=False)
|
|
129
|
+
port = config_get_int('messaging-cache', 'port')
|
|
130
|
+
reconnect_attempts = config_get_int('messaging-cache', 'reconnect_attempts', default=100)
|
|
131
|
+
ssl_key_file = config_get('messaging-cache', 'ssl_key_file', raise_exception=False)
|
|
132
|
+
ssl_cert_file = config_get('messaging-cache', 'ssl_cert_file', raise_exception=False)
|
|
133
|
+
|
|
134
|
+
stomp_conn_mngr = StompConnectionManager()
|
|
135
|
+
conns, _ = stomp_conn_mngr.re_configure(
|
|
136
|
+
brokers=brokers,
|
|
137
|
+
port=port,
|
|
138
|
+
use_ssl=use_ssl,
|
|
139
|
+
vhost=vhost,
|
|
140
|
+
reconnect_attempts=reconnect_attempts,
|
|
141
|
+
ssl_key_file=ssl_key_file,
|
|
142
|
+
ssl_cert_file=ssl_cert_file,
|
|
143
|
+
timeout=None,
|
|
144
|
+
logger=logger
|
|
145
|
+
)
|
|
90
146
|
|
|
91
147
|
logger(logging.INFO, 'consumer started')
|
|
92
148
|
|
|
93
|
-
conn_mgr.set_listener_factory('rucio-cache-consumer', AMQConsumer, heartbeats=conn_mgr.config.heartbeats)
|
|
94
|
-
|
|
95
149
|
while not GRACEFUL_STOP.is_set():
|
|
150
|
+
for conn in conns:
|
|
151
|
+
if not conn.is_connected():
|
|
152
|
+
host_port = conn.transport._Transport__host_and_ports[0]
|
|
153
|
+
|
|
154
|
+
logger(logging.INFO, 'connecting to %s' % host_port[0])
|
|
155
|
+
METRICS.counter('reconnect.{host}').labels(host=host_port[0]).inc()
|
|
156
|
+
conn.set_listener('rucio-cache-consumer', AMQConsumer(broker=host_port, conn=conn, logger=logger))
|
|
157
|
+
if not use_ssl:
|
|
158
|
+
conn.connect(username, password)
|
|
159
|
+
else:
|
|
160
|
+
conn.connect()
|
|
96
161
|
|
|
97
|
-
|
|
162
|
+
conn.subscribe(destination=destination, ack='auto', id=subscription_id)
|
|
98
163
|
time.sleep(1)
|
|
99
164
|
|
|
100
165
|
logger(logging.INFO, 'graceful stop requested')
|
|
101
|
-
|
|
166
|
+
stomp_conn_mngr.disconnect()
|
|
102
167
|
logger(logging.INFO, 'graceful stop done')
|
|
103
168
|
|
|
104
169
|
|
|
105
|
-
def stop(signum:
|
|
170
|
+
def stop(signum: Optional[int] = None, frame: Optional["FrameType"] = None) -> None:
|
|
106
171
|
"""
|
|
107
172
|
Graceful exit.
|
|
108
173
|
"""
|
|
@@ -115,19 +180,18 @@ def run(num_thread: int = 1) -> None:
|
|
|
115
180
|
Starts up the rucio cache consumer thread
|
|
116
181
|
"""
|
|
117
182
|
setup_logging(process_name=DAEMON_NAME)
|
|
118
|
-
logger = formatted_logger(logging.log, DAEMON_NAME + ' %s')
|
|
119
183
|
|
|
120
184
|
if rucio.db.sqla.util.is_old_db():
|
|
121
185
|
raise exception.DatabaseException('Database was not updated, daemon won\'t start')
|
|
122
186
|
|
|
123
|
-
|
|
124
|
-
threads = [
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
threads.append(con_thread)
|
|
187
|
+
logging.info('starting consumer thread')
|
|
188
|
+
threads = [threading.Thread(target=consumer, kwargs={'id_': i, 'num_thread': num_thread})
|
|
189
|
+
for i in range(0, num_thread)]
|
|
190
|
+
|
|
191
|
+
[t.start() for t in threads]
|
|
129
192
|
|
|
130
|
-
|
|
193
|
+
logging.info('waiting for interrupts')
|
|
131
194
|
|
|
132
|
-
|
|
133
|
-
|
|
195
|
+
# Interruptible joins require a timeout.
|
|
196
|
+
while threads[0].is_alive():
|
|
197
|
+
[t.join(timeout=3.14) for t in threads]
|
|
@@ -15,18 +15,22 @@
|
|
|
15
15
|
"""
|
|
16
16
|
Conveyor is a daemon to manage file transfers.
|
|
17
17
|
"""
|
|
18
|
+
|
|
18
19
|
import json
|
|
19
20
|
import logging
|
|
21
|
+
import socket
|
|
20
22
|
import threading
|
|
21
23
|
import time
|
|
22
24
|
import traceback
|
|
23
|
-
from typing import TYPE_CHECKING, Any
|
|
25
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
26
|
+
|
|
27
|
+
import stomp
|
|
24
28
|
|
|
25
29
|
import rucio.db.sqla.util
|
|
26
30
|
from rucio.common import exception
|
|
27
|
-
from rucio.common.
|
|
31
|
+
from rucio.common.config import config_get, config_get_bool, config_get_int, config_get_list
|
|
32
|
+
from rucio.common.logging import setup_logging
|
|
28
33
|
from rucio.common.policy import get_policy
|
|
29
|
-
from rucio.common.stomp_utils import Connection, ListenerBase, StompConnectionManager
|
|
30
34
|
from rucio.core import request as request_core
|
|
31
35
|
from rucio.core import transfer as transfer_core
|
|
32
36
|
from rucio.core.monitor import MetricManager
|
|
@@ -49,22 +53,26 @@ GRACEFUL_STOP = threading.Event()
|
|
|
49
53
|
DAEMON_NAME = 'conveyor-receiver'
|
|
50
54
|
|
|
51
55
|
|
|
52
|
-
class Receiver
|
|
56
|
+
class Receiver:
|
|
53
57
|
|
|
54
|
-
def __init__(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
super().__init__(conn, logger, **kwargs)
|
|
58
|
+
def __init__(
|
|
59
|
+
self,
|
|
60
|
+
broker: str,
|
|
61
|
+
id_: str,
|
|
62
|
+
total_threads: int,
|
|
63
|
+
transfer_stats_manager: request_core.TransferStatsManager,
|
|
64
|
+
all_vos: bool = False
|
|
65
|
+
):
|
|
63
66
|
self.__all_vos = all_vos
|
|
67
|
+
self.__broker = broker
|
|
64
68
|
self.__id = id_
|
|
65
69
|
self.__total_threads = total_threads
|
|
66
70
|
self._transfer_stats_manager = transfer_stats_manager
|
|
67
71
|
|
|
72
|
+
@METRICS.count_it
|
|
73
|
+
def on_error(self, frame: "Frame") -> None:
|
|
74
|
+
logging.error('[%s] %s' % (self.__broker, frame.body))
|
|
75
|
+
|
|
68
76
|
@METRICS.count_it
|
|
69
77
|
def on_message(self, frame: "Frame") -> None:
|
|
70
78
|
msg = json.loads(frame.body) # type: ignore
|
|
@@ -78,8 +86,7 @@ class Receiver(ListenerBase):
|
|
|
78
86
|
and 'issuer' in msg['job_metadata'].keys() \
|
|
79
87
|
and str(msg['job_metadata']['issuer']) == 'rucio':
|
|
80
88
|
|
|
81
|
-
if
|
|
82
|
-
or msg.get('job_multihop', False) is True)):
|
|
89
|
+
if 'job_state' in msg.keys() and (str(msg['job_state']) != 'ACTIVE' or msg.get('job_multihop', False) is True):
|
|
83
90
|
METRICS.counter('message_rucio').inc()
|
|
84
91
|
|
|
85
92
|
self._perform_request_update(msg)
|
|
@@ -89,15 +96,13 @@ class Receiver(ListenerBase):
|
|
|
89
96
|
self,
|
|
90
97
|
msg: dict[str, Any],
|
|
91
98
|
*,
|
|
92
|
-
session: "Session
|
|
99
|
+
session: Optional["Session"] = None,
|
|
93
100
|
logger: "LoggerFunction" = logging.log
|
|
94
101
|
) -> None:
|
|
95
102
|
external_host = msg.get('endpnt', None)
|
|
96
103
|
request_id = msg['file_metadata'].get('request_id', None)
|
|
97
104
|
try:
|
|
98
|
-
tt_status_report = FTS3CompletionMessageTransferStatusReport(external_host,
|
|
99
|
-
request_id=request_id,
|
|
100
|
-
fts_message=msg)
|
|
105
|
+
tt_status_report = FTS3CompletionMessageTransferStatusReport(external_host, request_id=request_id, fts_message=msg)
|
|
101
106
|
if tt_status_report.get_db_fields_to_update(session=session, logger=logger): # type: ignore
|
|
102
107
|
logging.info('RECEIVED %s', tt_status_report)
|
|
103
108
|
|
|
@@ -115,39 +120,103 @@ class Receiver(ListenerBase):
|
|
|
115
120
|
logging.critical(traceback.format_exc())
|
|
116
121
|
|
|
117
122
|
|
|
118
|
-
def receiver(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
def receiver(
|
|
124
|
+
id_: str,
|
|
125
|
+
total_threads: int = 1,
|
|
126
|
+
all_vos: bool = False
|
|
127
|
+
) -> None:
|
|
122
128
|
"""
|
|
123
129
|
Main loop to consume messages from the FTS3 producer.
|
|
124
130
|
"""
|
|
125
|
-
logger(logging.INFO, 'receiver starting')
|
|
126
|
-
|
|
127
|
-
conn_mgr = StompConnectionManager(config_section='messaging-fts3', logger=logger)
|
|
128
131
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
+
logging.info('receiver starting')
|
|
133
|
+
|
|
134
|
+
brokers_alias = []
|
|
135
|
+
brokers_resolved = []
|
|
136
|
+
try:
|
|
137
|
+
brokers_alias = config_get_list('messaging-fts3', 'brokers')
|
|
138
|
+
except Exception:
|
|
139
|
+
raise Exception('Could not load brokers from configuration')
|
|
140
|
+
|
|
141
|
+
logging.info('resolving broker dns alias: %s' % brokers_alias)
|
|
142
|
+
|
|
143
|
+
brokers_resolved = []
|
|
144
|
+
for broker in brokers_alias:
|
|
145
|
+
addrinfos = socket.getaddrinfo(broker, 0, socket.AF_INET, 0, socket.IPPROTO_TCP)
|
|
146
|
+
brokers_resolved.extend(ai[4][0] for ai in addrinfos)
|
|
147
|
+
|
|
148
|
+
logging.info('brokers resolved to %s', brokers_resolved)
|
|
149
|
+
|
|
150
|
+
logging.info('checking authentication method')
|
|
151
|
+
use_ssl = True
|
|
152
|
+
try:
|
|
153
|
+
use_ssl = config_get_bool('messaging-fts3', 'use_ssl')
|
|
154
|
+
except:
|
|
155
|
+
logging.info('could not find use_ssl in configuration -- please update your rucio.cfg')
|
|
156
|
+
|
|
157
|
+
port = config_get_int('messaging-fts3', 'port')
|
|
158
|
+
vhost = config_get('messaging-fts3', 'broker_virtual_host', raise_exception=False)
|
|
159
|
+
if not use_ssl:
|
|
160
|
+
username = config_get('messaging-fts3', 'username')
|
|
161
|
+
password = config_get('messaging-fts3', 'password')
|
|
162
|
+
port = config_get_int('messaging-fts3', 'nonssl_port')
|
|
163
|
+
|
|
164
|
+
conns = []
|
|
165
|
+
for broker in brokers_resolved:
|
|
166
|
+
if not use_ssl:
|
|
167
|
+
logging.info('setting up username/password authentication: %s' % broker)
|
|
168
|
+
else:
|
|
169
|
+
logging.info('setting up ssl cert/key authentication: %s' % broker)
|
|
170
|
+
con = stomp.Connection12(host_and_ports=[(broker, port)],
|
|
171
|
+
vhost=vhost,
|
|
172
|
+
reconnect_attempts_max=999)
|
|
173
|
+
if use_ssl:
|
|
174
|
+
con.set_ssl(
|
|
175
|
+
key_file=config_get('messaging-fts3', 'ssl_key_file'),
|
|
176
|
+
cert_file=config_get('messaging-fts3', 'ssl_cert_file'),
|
|
177
|
+
)
|
|
178
|
+
conns.append(con)
|
|
179
|
+
|
|
180
|
+
logging.info('receiver started')
|
|
181
|
+
|
|
182
|
+
with (HeartbeatHandler(executable=DAEMON_NAME, renewal_interval=30) as heartbeat_handler,
|
|
132
183
|
request_core.TransferStatsManager() as transfer_stats_manager):
|
|
133
|
-
|
|
134
|
-
conn_mgr.set_listener_factory('rucio-messaging-fts3', Receiver,
|
|
135
|
-
id_=id_,
|
|
136
|
-
total_threads=total_threads,
|
|
137
|
-
transfer_stats_manager=transfer_stats_manager,
|
|
138
|
-
all_vos=all_vos,
|
|
139
|
-
heartbeats=conn_mgr.config.heartbeats)
|
|
140
|
-
|
|
141
184
|
while not GRACEFUL_STOP.is_set():
|
|
142
185
|
|
|
143
|
-
|
|
144
|
-
|
|
186
|
+
_, _, logger = heartbeat_handler.live()
|
|
187
|
+
|
|
188
|
+
for conn in conns:
|
|
189
|
+
|
|
190
|
+
if not conn.is_connected():
|
|
191
|
+
logger(logging.INFO, 'connecting to %s' % conn.transport._Transport__host_and_ports[0][0])
|
|
192
|
+
METRICS.counter('reconnect.{host}').labels(host=conn.transport._Transport__host_and_ports[0][0].split('.')[0]).inc()
|
|
193
|
+
|
|
194
|
+
conn.set_listener(
|
|
195
|
+
'rucio-messaging-fts3',
|
|
196
|
+
Receiver(
|
|
197
|
+
broker=conn.transport._Transport__host_and_ports[0],
|
|
198
|
+
id_=id_,
|
|
199
|
+
total_threads=total_threads,
|
|
200
|
+
transfer_stats_manager=transfer_stats_manager,
|
|
201
|
+
all_vos=all_vos
|
|
202
|
+
))
|
|
203
|
+
if not use_ssl:
|
|
204
|
+
conn.connect(username, password, wait=True)
|
|
205
|
+
else:
|
|
206
|
+
conn.connect(wait=True)
|
|
207
|
+
conn.subscribe(destination=config_get('messaging-fts3', 'destination'),
|
|
208
|
+
id='rucio-messaging-fts3',
|
|
209
|
+
ack='auto')
|
|
145
210
|
time.sleep(1)
|
|
146
211
|
|
|
147
|
-
|
|
212
|
+
for conn in conns:
|
|
213
|
+
try:
|
|
214
|
+
conn.disconnect()
|
|
215
|
+
except Exception:
|
|
216
|
+
pass
|
|
148
217
|
|
|
149
218
|
|
|
150
|
-
def stop(signum:
|
|
219
|
+
def stop(signum: Optional[int] = None, frame: Optional["FrameType"] = None) -> None:
|
|
151
220
|
"""
|
|
152
221
|
Graceful exit.
|
|
153
222
|
"""
|
|
@@ -155,25 +224,26 @@ def stop(signum: "int | None" = None, frame: "FrameType | None" = None) -> None:
|
|
|
155
224
|
GRACEFUL_STOP.set()
|
|
156
225
|
|
|
157
226
|
|
|
158
|
-
def run(
|
|
227
|
+
def run(
|
|
228
|
+
once: bool = False,
|
|
229
|
+
total_threads: int = 1
|
|
230
|
+
) -> None:
|
|
159
231
|
"""
|
|
160
232
|
Starts up the receiver thread
|
|
161
233
|
"""
|
|
162
234
|
setup_logging(process_name=DAEMON_NAME)
|
|
163
|
-
logger = formatted_logger(logging.log, DAEMON_NAME + ' %s')
|
|
164
235
|
|
|
165
236
|
if rucio.db.sqla.util.is_old_db():
|
|
166
237
|
raise exception.DatabaseException('Database was not updated, daemon won\'t start')
|
|
167
238
|
|
|
168
|
-
|
|
169
|
-
threads = [
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
rec_thread.start()
|
|
174
|
-
threads.append(rec_thread)
|
|
239
|
+
logging.info('starting receiver thread')
|
|
240
|
+
threads = [threading.Thread(target=receiver, kwargs={'id_': i,
|
|
241
|
+
'total_threads': total_threads}) for i in range(0, total_threads)]
|
|
242
|
+
|
|
243
|
+
[thread.start() for thread in threads]
|
|
175
244
|
|
|
176
|
-
|
|
245
|
+
logging.info('waiting for interrupts')
|
|
177
246
|
|
|
178
|
-
|
|
179
|
-
|
|
247
|
+
# Interruptible joins require a timeout.
|
|
248
|
+
while threads:
|
|
249
|
+
threads = [thread.join(timeout=3.14) for thread in threads if thread and thread.is_alive()]
|