rucio 37.0.0rc2__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.

Files changed (67) hide show
  1. rucio/common/stomp_utils.py +119 -383
  2. rucio/daemons/cache/consumer.py +90 -26
  3. rucio/daemons/conveyor/receiver.py +123 -53
  4. rucio/daemons/hermes/hermes.py +344 -43
  5. rucio/daemons/tracer/kronos.py +139 -114
  6. rucio/vcsversion.py +3 -3
  7. {rucio-37.0.0rc2.dist-info → rucio-37.0.0rc4.dist-info}/METADATA +1 -1
  8. {rucio-37.0.0rc2.dist-info → rucio-37.0.0rc4.dist-info}/RECORD +67 -67
  9. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/alembic.ini.template +0 -0
  10. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/alembic_offline.ini.template +0 -0
  11. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/globus-config.yml.template +0 -0
  12. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/ldap.cfg.template +0 -0
  13. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
  14. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
  15. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
  16. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
  17. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
  18. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
  19. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
  20. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/rucio.cfg.atlas.client.template +0 -0
  21. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/rucio.cfg.template +0 -0
  22. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/etc/rucio_multi_vo.cfg.template +0 -0
  23. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/requirements.server.txt +0 -0
  24. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/tools/bootstrap.py +0 -0
  25. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/tools/merge_rucio_configs.py +0 -0
  26. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/data/rucio/tools/reset_database.py +0 -0
  27. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio +0 -0
  28. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-abacus-account +0 -0
  29. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-abacus-collection-replica +0 -0
  30. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-abacus-rse +0 -0
  31. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-admin +0 -0
  32. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-atropos +0 -0
  33. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-auditor +0 -0
  34. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-automatix +0 -0
  35. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-bb8 +0 -0
  36. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-cache-client +0 -0
  37. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-cache-consumer +0 -0
  38. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-finisher +0 -0
  39. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-poller +0 -0
  40. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-preparer +0 -0
  41. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-receiver +0 -0
  42. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-stager +0 -0
  43. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-submitter +0 -0
  44. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-conveyor-throttler +0 -0
  45. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-dark-reaper +0 -0
  46. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-dumper +0 -0
  47. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-follower +0 -0
  48. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-hermes +0 -0
  49. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-judge-cleaner +0 -0
  50. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-judge-evaluator +0 -0
  51. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-judge-injector +0 -0
  52. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-judge-repairer +0 -0
  53. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-kronos +0 -0
  54. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-minos +0 -0
  55. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-minos-temporary-expiration +0 -0
  56. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-necromancer +0 -0
  57. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-oauth-manager +0 -0
  58. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-reaper +0 -0
  59. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-replica-recoverer +0 -0
  60. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-rse-decommissioner +0 -0
  61. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-storage-consistency-actions +0 -0
  62. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-transmogrifier +0 -0
  63. {rucio-37.0.0rc2.data → rucio-37.0.0rc4.data}/scripts/rucio-undertaker +0 -0
  64. {rucio-37.0.0rc2.dist-info → rucio-37.0.0rc4.dist-info}/WHEEL +0 -0
  65. {rucio-37.0.0rc2.dist-info → rucio-37.0.0rc4.dist-info}/licenses/AUTHORS.rst +0 -0
  66. {rucio-37.0.0rc2.dist-info → rucio-37.0.0rc4.dist-info}/licenses/LICENSE +0 -0
  67. {rucio-37.0.0rc2.dist-info → rucio-37.0.0rc4.dist-info}/top_level.txt +0 -0
@@ -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 ListenerBase, StompConnectionManager
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(ListenerBase):
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._logger(logging.DEBUG, 'Message received: %s', msg)
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 = f"{rse_vo_str} on {msg['vo']}"
96
+ rse_vo_str = '{} on {}'.format(rse_vo_str, msg['vo'])
71
97
  if msg['operation'] == 'add_replicas':
72
- self._logger(logging.INFO, "add_replicas to RSE %s: %s", rse_vo_str, str(msg['files']))
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._logger(logging.INFO, "delete_replicas to RSE %s: %s", rse_vo_str, str(msg['files']))
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._logger(logging.DEBUG, 'Check failed: %s %s', isinstance(msg, dict), "operation" in msg.keys())
104
+ self.__logger(logging.DEBUG, 'Check failed: %s %s '
105
+ % (isinstance(msg, dict), 'operation' in msg.keys()))
79
106
  except:
80
- self._logger(logging.ERROR, str(format_exc()))
107
+ self.__logger(logging.ERROR, str(format_exc()))
81
108
 
82
109
 
83
- def consumer(id_: int, num_thread: int = 1, logger: LoggerFunction = logging.log) -> None:
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
- conn_mgr = StompConnectionManager(config_section='messaging-cache', logger=logger)
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
- conn_mgr.subscribe(id_='rucio-cache-messaging', ack='auto')
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
- conn_mgr.disconnect()
166
+ stomp_conn_mngr.disconnect()
102
167
  logger(logging.INFO, 'graceful stop done')
103
168
 
104
169
 
105
- def stop(signum: "int | None" = None, frame: "FrameType | None" = None) -> None:
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
- logger(logging.INFO, 'starting consumer thread')
124
- threads = []
125
- for i in range(num_thread):
126
- con_thread = threading.Thread(target=consumer, kwargs={'id_': i, 'num_thread': num_thread, 'logger': logger})
127
- con_thread.start()
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
- logger(logging.INFO, 'waiting for interrupts')
193
+ logging.info('waiting for interrupts')
131
194
 
132
- while [thread.join(timeout=3.14) for thread in threads if thread.is_alive()]:
133
- pass
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.logging import formatted_logger, setup_logging
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(ListenerBase):
56
+ class Receiver:
53
57
 
54
- def __init__(self,
55
- conn: Connection,
56
- id_: str,
57
- total_threads: int,
58
- transfer_stats_manager: request_core.TransferStatsManager,
59
- all_vos: bool = False,
60
- logger: "LoggerFunction" = logging.log,
61
- **kwargs: dict) -> None:
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 ('job_state' in msg.keys() and (str(msg['job_state']) != 'ACTIVE'
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 | None",
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(id_: str,
119
- total_threads: int = 1,
120
- all_vos: bool = False,
121
- logger: "LoggerFunction" = logging.log):
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
- logger(logging.INFO, 'receiver started')
130
-
131
- with (HeartbeatHandler(executable=DAEMON_NAME, renewal_interval=30),
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
- conn_mgr.subscribe(id_='rucio-messaging-fts3', ack='auto')
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
- conn_mgr.disconnect()
212
+ for conn in conns:
213
+ try:
214
+ conn.disconnect()
215
+ except Exception:
216
+ pass
148
217
 
149
218
 
150
- def stop(signum: "int | None" = None, frame: "FrameType | None" = None) -> None:
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(once: bool = False, total_threads: int = 1) -> None:
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
- logger(logging.INFO, 'starting receiver thread')
169
- threads = []
170
- for i in range(total_threads):
171
- rec_thread = threading.Thread(target=receiver,
172
- kwargs={'id_': i, 'logger': logger, 'total_threads': total_threads})
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
- logger(logging.INFO, 'waiting for interrupts')
245
+ logging.info('waiting for interrupts')
177
246
 
178
- while [thread.join(timeout=3.14) for thread in threads if thread.is_alive()]:
179
- pass
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()]