nost-tools 2.0.3__py3-none-any.whl → 2.0.5__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 nost-tools might be problematic. Click here for more details.
- nost_tools/__init__.py +1 -1
- nost_tools/manager.py +97 -48
- {nost_tools-2.0.3.dist-info → nost_tools-2.0.5.dist-info}/METADATA +1 -1
- {nost_tools-2.0.3.dist-info → nost_tools-2.0.5.dist-info}/RECORD +7 -7
- {nost_tools-2.0.3.dist-info → nost_tools-2.0.5.dist-info}/WHEEL +1 -1
- {nost_tools-2.0.3.dist-info → nost_tools-2.0.5.dist-info}/licenses/LICENSE +0 -0
- {nost_tools-2.0.3.dist-info → nost_tools-2.0.5.dist-info}/top_level.txt +0 -0
nost_tools/__init__.py
CHANGED
nost_tools/manager.py
CHANGED
|
@@ -98,7 +98,51 @@ class Manager(Application):
|
|
|
98
98
|
auto_delete=True,
|
|
99
99
|
)
|
|
100
100
|
|
|
101
|
-
def
|
|
101
|
+
def _sleep_with_heartbeat(self, total_seconds):
|
|
102
|
+
"""
|
|
103
|
+
Sleep for a specified number of seconds while allowing connection heartbeats.
|
|
104
|
+
Works with SelectConnection by using short sleep intervals.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
total_seconds (float): Total number of seconds to sleep
|
|
108
|
+
"""
|
|
109
|
+
if total_seconds <= 0:
|
|
110
|
+
return
|
|
111
|
+
|
|
112
|
+
# Sleep in smaller chunks to allow heartbeats to pass through
|
|
113
|
+
check_interval = 30 # Check every 30 seconds at most
|
|
114
|
+
end_time = time.time() + total_seconds
|
|
115
|
+
|
|
116
|
+
logger.debug(f"Starting heartbeat-safe sleep for {total_seconds:.2f} seconds")
|
|
117
|
+
|
|
118
|
+
while time.time() < end_time:
|
|
119
|
+
# Calculate remaining time
|
|
120
|
+
remaining = end_time - time.time()
|
|
121
|
+
|
|
122
|
+
# Sleep for the shorter of check_interval or remaining time
|
|
123
|
+
sleep_time = min(check_interval, remaining)
|
|
124
|
+
|
|
125
|
+
if sleep_time > 0:
|
|
126
|
+
time.sleep(sleep_time)
|
|
127
|
+
logger.debug(
|
|
128
|
+
f"Heartbeat check: {remaining:.2f} seconds remaining in sleep"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
def execute_test_plan(self, *args, **kwargs) -> None:
|
|
132
|
+
"""
|
|
133
|
+
Starts the test plan execution in a background thread.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
*args: Positional arguments to be passed to the test plan execution.
|
|
137
|
+
**kwargs: Keyword arguments to be passed to the test plan execution.
|
|
138
|
+
"""
|
|
139
|
+
thread = threading.Thread(
|
|
140
|
+
target=self._execute_test_plan_impl, args=args, kwargs=kwargs, daemon=True
|
|
141
|
+
)
|
|
142
|
+
logger.debug("Running test plan in background thread.")
|
|
143
|
+
thread.start()
|
|
144
|
+
|
|
145
|
+
def _execute_test_plan_impl(
|
|
102
146
|
self,
|
|
103
147
|
sim_start_time: datetime = None,
|
|
104
148
|
sim_stop_time: datetime = None,
|
|
@@ -133,6 +177,7 @@ class Manager(Application):
|
|
|
133
177
|
init_retry_delay_s (float): number of seconds to wait between initialization commands while waiting for required applications
|
|
134
178
|
init_max_retry (int): number of initialization commands while waiting for required applications before continuing to execution
|
|
135
179
|
"""
|
|
180
|
+
# Initialize parameters from arguments or config
|
|
136
181
|
if sim_start_time is not None and sim_stop_time is not None:
|
|
137
182
|
self.sim_start_time = sim_start_time
|
|
138
183
|
self.sim_stop_time = sim_stop_time
|
|
@@ -163,9 +208,6 @@ class Manager(Application):
|
|
|
163
208
|
self.time_status_step = parameters.time_status_step
|
|
164
209
|
self.time_status_init = parameters.time_status_init
|
|
165
210
|
self.command_lead = parameters.command_lead
|
|
166
|
-
# self.required_apps = (
|
|
167
|
-
# self.config.rc.simulation_configuration.execution_parameters.required_apps
|
|
168
|
-
# )
|
|
169
211
|
self.required_apps = [
|
|
170
212
|
app for app in parameters.required_apps if app != self.app_name
|
|
171
213
|
]
|
|
@@ -175,13 +217,10 @@ class Manager(Application):
|
|
|
175
217
|
raise ValueError(
|
|
176
218
|
"No configuration runtime. Please provide simulation start and stop times."
|
|
177
219
|
)
|
|
178
|
-
|
|
220
|
+
|
|
179
221
|
self.establish_exchange()
|
|
180
|
-
# if self.predefined_exchanges_queues:
|
|
181
|
-
# self.declare_exchange()
|
|
182
|
-
# self.declare_bind_queue()
|
|
183
|
-
####
|
|
184
222
|
|
|
223
|
+
# Set up tracking of required applications
|
|
185
224
|
self.required_apps_status = dict(
|
|
186
225
|
zip(self.required_apps, [False] * len(self.required_apps))
|
|
187
226
|
)
|
|
@@ -189,35 +228,37 @@ class Manager(Application):
|
|
|
189
228
|
self.add_message_callback("*", "status.time", self.on_app_time_status)
|
|
190
229
|
|
|
191
230
|
self._create_time_status_publisher(self.time_status_step, self.time_status_init)
|
|
231
|
+
|
|
232
|
+
# Initialize with retry logic
|
|
192
233
|
for i in range(self.init_max_retry):
|
|
193
|
-
# issue the init command
|
|
194
234
|
self.init(self.sim_start_time, self.sim_stop_time, self.required_apps)
|
|
195
235
|
next_try = self.simulator.get_wallclock_time() + timedelta(
|
|
196
236
|
seconds=self.init_retry_delay_s
|
|
197
237
|
)
|
|
198
|
-
# wait until all required apps are ready
|
|
199
238
|
while (
|
|
200
239
|
not all([self.required_apps_status[app] for app in self.required_apps])
|
|
201
240
|
and self.simulator.get_wallclock_time() < next_try
|
|
202
241
|
):
|
|
203
242
|
time.sleep(0.001)
|
|
204
|
-
|
|
205
|
-
#
|
|
206
|
-
# configure start time
|
|
243
|
+
|
|
244
|
+
# Configure start time if not provided
|
|
207
245
|
if self.start_time is None:
|
|
208
246
|
self.start_time = self.simulator.get_wallclock_time() + self.command_lead
|
|
209
|
-
|
|
210
|
-
time
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
)
|
|
217
|
-
/ timedelta(seconds=1),
|
|
247
|
+
|
|
248
|
+
# Sleep until start time using heartbeat-safe approach
|
|
249
|
+
sleep_seconds = max(
|
|
250
|
+
0,
|
|
251
|
+
(
|
|
252
|
+
(self.start_time - self.simulator.get_wallclock_time())
|
|
253
|
+
- self.command_lead
|
|
218
254
|
)
|
|
255
|
+
/ timedelta(seconds=1),
|
|
219
256
|
)
|
|
220
|
-
|
|
257
|
+
|
|
258
|
+
# Use our heartbeat-safe sleep
|
|
259
|
+
self._sleep_with_heartbeat(sleep_seconds)
|
|
260
|
+
|
|
261
|
+
# Issue the start command
|
|
221
262
|
self.start(
|
|
222
263
|
self.sim_start_time,
|
|
223
264
|
self.sim_stop_time,
|
|
@@ -227,43 +268,51 @@ class Manager(Application):
|
|
|
227
268
|
self.time_status_step,
|
|
228
269
|
self.time_status_init,
|
|
229
270
|
)
|
|
230
|
-
|
|
271
|
+
|
|
272
|
+
# Wait for simulation to start executing
|
|
231
273
|
while self.simulator.get_mode() != Mode.EXECUTING:
|
|
232
274
|
time.sleep(0.001)
|
|
275
|
+
|
|
276
|
+
# Process time scale updates
|
|
233
277
|
for update in self.time_scale_updates:
|
|
234
278
|
update_time = self.simulator.get_wallclock_time_at_simulation_time(
|
|
235
279
|
update.sim_update_time
|
|
236
280
|
)
|
|
237
|
-
#
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
(
|
|
242
|
-
|
|
243
|
-
- self.command_lead
|
|
244
|
-
)
|
|
245
|
-
/ timedelta(seconds=1),
|
|
281
|
+
# Sleep until update time using heartbeat-safe approach
|
|
282
|
+
sleep_seconds = max(
|
|
283
|
+
0,
|
|
284
|
+
(
|
|
285
|
+
(update_time - self.simulator.get_wallclock_time())
|
|
286
|
+
- self.command_lead
|
|
246
287
|
)
|
|
288
|
+
/ timedelta(seconds=1),
|
|
247
289
|
)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
#
|
|
290
|
+
|
|
291
|
+
# Use our heartbeat-safe sleep
|
|
292
|
+
self._sleep_with_heartbeat(sleep_seconds)
|
|
293
|
+
|
|
294
|
+
# Issue the update command
|
|
295
|
+
self.update(update.time_scale_factor, update.sim_update_time)
|
|
296
|
+
|
|
297
|
+
# Wait until update takes effect
|
|
253
298
|
while self.simulator.get_time_scale_factor() != update.time_scale_factor:
|
|
254
|
-
time.sleep(
|
|
299
|
+
time.sleep(0.001)
|
|
300
|
+
|
|
255
301
|
end_time = self.simulator.get_wallclock_time_at_simulation_time(
|
|
256
302
|
self.simulator.get_end_time()
|
|
257
303
|
)
|
|
258
|
-
|
|
259
|
-
time
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
)
|
|
304
|
+
|
|
305
|
+
# Sleep until stop time using heartbeat-safe approach
|
|
306
|
+
sleep_seconds = max(
|
|
307
|
+
0,
|
|
308
|
+
((end_time - self.simulator.get_wallclock_time()) - self.command_lead)
|
|
309
|
+
/ timedelta(seconds=1),
|
|
265
310
|
)
|
|
266
|
-
|
|
311
|
+
|
|
312
|
+
# Use our heartbeat-safe sleep
|
|
313
|
+
self._sleep_with_heartbeat(sleep_seconds)
|
|
314
|
+
|
|
315
|
+
# Issue the stop command
|
|
267
316
|
self.stop(self.sim_stop_time)
|
|
268
317
|
|
|
269
318
|
def on_app_ready_status(self, ch, method, properties, body) -> None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nost_tools
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.5
|
|
4
4
|
Summary: Tools for Novel Observing Strategies Testbed (NOS-T) Applications
|
|
5
5
|
Author-email: "Paul T. Grogan" <paul.grogan@asu.edu>, "Emmanuel M. Gonzalez" <emmanuelgonzalez@asu.edu>
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
nost_tools/__init__.py,sha256=
|
|
1
|
+
nost_tools/__init__.py,sha256=wtJclxK6ZfF7GpmfBfOz2YKp-zFw-kO9B49LJeTb1Vw,873
|
|
2
2
|
nost_tools/application.py,sha256=1mFCw6b5BCAlaof-ijzjFYCvVB-WCn9llpHHijxeIik,37027
|
|
3
3
|
nost_tools/application_utils.py,sha256=_R39D26FYxgaO4uyTON24KXc4UQ4zAEDBZfEkHbEw64,9386
|
|
4
4
|
nost_tools/configuration.py,sha256=ikNpZi8aofhZzJRbJf4x46afbAnp8r5C7Yr50Rnn1Nc,11639
|
|
@@ -6,13 +6,13 @@ nost_tools/entity.py,sha256=AwbZMP3_H4RQuyU4voyQwYFkETxG0mfD-0BMHxrRFf8,2064
|
|
|
6
6
|
nost_tools/errors.py,sha256=0JcDlMEkZAya3-5c0rRozLuxp8qF58StG4JgRsaxfKU,344
|
|
7
7
|
nost_tools/logger_application.py,sha256=rxPBfyA7Zym5b_EsoSJvT9JWNIVWZX1a-4czFwCqaQ4,7217
|
|
8
8
|
nost_tools/managed_application.py,sha256=jjS-URl4D_-VwKNYnqwYg_myFugKgMd_Gy1aAxxw0SU,11514
|
|
9
|
-
nost_tools/manager.py,sha256=
|
|
9
|
+
nost_tools/manager.py,sha256=i0lNPlUrj3Cm-F_kFOa0vL4dH95PTomsLvESvMrDrUA,21316
|
|
10
10
|
nost_tools/observer.py,sha256=w66jZQ11Fr7XSCcvcc2f5ISce2n8Ba7cXqheSTuyrmw,5519
|
|
11
11
|
nost_tools/publisher.py,sha256=omU8tb0AXnA6RfhYSh0vnXbJtrRo4ukx1J5ANl4bDLQ,5291
|
|
12
12
|
nost_tools/schemas.py,sha256=m6Np7DGrBIgtswpnrTqSowTb_niC4NY59BTQFBYfkZc,15332
|
|
13
13
|
nost_tools/simulator.py,sha256=ALnGDmnA_ga-1Lq-bVWi2vcrspgjS4vtuDE0jWsI7fE,20191
|
|
14
|
-
nost_tools-2.0.
|
|
15
|
-
nost_tools-2.0.
|
|
16
|
-
nost_tools-2.0.
|
|
17
|
-
nost_tools-2.0.
|
|
18
|
-
nost_tools-2.0.
|
|
14
|
+
nost_tools-2.0.5.dist-info/licenses/LICENSE,sha256=aAMU-mTHTKpWkBsg9QhkhCQpEm3Gri7J_fVuJov8s3s,1539
|
|
15
|
+
nost_tools-2.0.5.dist-info/METADATA,sha256=rJzfSSuz40c1VYpDojXIcZoYgLv9twTxG8oSt4URP3g,4256
|
|
16
|
+
nost_tools-2.0.5.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
|
|
17
|
+
nost_tools-2.0.5.dist-info/top_level.txt,sha256=LNChUgrv2-wiym12O0r61kY83COjTpTiJ2Ly1Ca58A8,11
|
|
18
|
+
nost_tools-2.0.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|