Skip to content

Commit d95f8eb

Browse files
Merge pull request #232 from simonsobs/koopman/sigint-handling
Add signal handling during shutdown operations
2 parents 7b69a23 + 04c527c commit d95f8eb

File tree

6 files changed

+76
-37
lines changed

6 files changed

+76
-37
lines changed

src/sorunlib/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import signal
2+
13
from . import acu, hwp, seq, smurf, stimulator, wiregrid
24

35
from .commands import wait_until
@@ -27,6 +29,15 @@ def initialize(test_mode=False):
2729
"wait_until",
2830
"initialize"]
2931

32+
33+
# Treat SIGTERM like SIGINT and raise an exception
34+
def term_handler(sig, frame):
35+
raise KeyboardInterrupt
36+
37+
38+
signal.signal(signal.SIGTERM, term_handler)
39+
40+
3041
# Define the variable '__version__':
3142
# This has the closest behavior to versioneer that I could find
3243
# https://github.com/maresb/hatch-vcs-footgun-example

src/sorunlib/_internal.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55
"""
66

77
import datetime as dt
8+
import signal
89
import time
910

11+
from functools import wraps
12+
1013
import ocs
14+
import sorunlib as run
1115

1216
from sorunlib.commands import _timestamp_to_utc_datetime
1317

@@ -180,3 +184,39 @@ def monitor_process(client, operation, stop_time, check_interval=10):
180184

181185
# Recompute diff
182186
diff = _seconds_until_target(stop_time)
187+
188+
189+
def protect_shutdown(f):
190+
"""Decorator to install temporary signal handlers while operations required
191+
to safely shutdown are handled.
192+
193+
This will catch and print the caught signals to ``stdout`` while shutdown
194+
is happening. Currently handles only ``SIGINT`` and ``SIGTERM``.
195+
196+
"""
197+
@wraps(f)
198+
def wrapper(*args, **kwds):
199+
def handler(sig, frame):
200+
print(f'Caught {signal.Signals(sig).name} during shutdown.')
201+
202+
int_handler = signal.signal(signal.SIGINT, handler)
203+
term_handler = signal.signal(signal.SIGTERM, handler)
204+
205+
result = f(*args, **kwds)
206+
207+
signal.signal(signal.SIGINT, int_handler)
208+
signal.signal(signal.SIGTERM, term_handler)
209+
return result
210+
return wrapper
211+
212+
213+
@protect_shutdown
214+
def stop_smurfs():
215+
"""Simple wrapper to shutdown all SMuRF systems and handle any errors that
216+
occur.
217+
218+
"""
219+
try:
220+
run.smurf.stream('off')
221+
except RuntimeError as e:
222+
print(f"Caught error while shutting down SMuRF streams: {e}")

src/sorunlib/hwp.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import sorunlib as run
2-
from sorunlib._internal import check_response
2+
from sorunlib._internal import check_response, stop_smurfs
33

44

55
def _get_direction():
@@ -74,7 +74,7 @@ def spin_up(freq):
7474
check_response(hwp, resp)
7575
run.hwp.set_freq(freq=freq, timeout=1800)
7676
finally:
77-
run.smurf.stream('off')
77+
stop_smurfs()
7878

7979

8080
def spin_down(active=True, brake_voltage=None):
@@ -97,7 +97,7 @@ def spin_down(active=True, brake_voltage=None):
9797
resp = hwp.disable_driver_board()
9898
check_response(hwp, resp)
9999
finally:
100-
run.smurf.stream('off')
100+
stop_smurfs()
101101

102102

103103
def stop(active=True, brake_voltage=None):

src/sorunlib/seq.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,22 @@
44
import sorunlib as run
55

66
from sorunlib.commands import _timestamp_to_utc_datetime
7-
from sorunlib._internal import check_response, check_started, monitor_process
7+
from sorunlib._internal import check_response, check_started, monitor_process, protect_shutdown, stop_smurfs
88

99

1010
OP_TIMEOUT = 60
1111

1212

13-
def _stop_smurfs():
14-
# Stop SMuRF streams
15-
try:
16-
run.smurf.stream('off')
17-
except RuntimeError as e:
18-
print(f"Caught error while shutting down SMuRF streams: {e}")
19-
20-
13+
@protect_shutdown
2114
def _stop_scan():
2215
acu = run.CLIENTS['acu']
2316

2417
print("Stopping scan.")
25-
_stop_smurfs()
18+
stop_smurfs()
2619

2720
# Stop motion
2821
acu.generate_scan.stop()
22+
print("Waiting for telescope motion to stop.")
2923
resp = acu.generate_scan.wait(timeout=OP_TIMEOUT)
3024
check_response(acu, resp)
3125
print("Scan finished.")
@@ -66,10 +60,10 @@ def scan(description, stop_time, width, az_drift=0, tag=None, subtype=None,
6660

6761
acu = run.CLIENTS['acu']
6862

69-
# Enable SMuRF streams
70-
run.smurf.stream('on', subtype=subtype, tag=tag)
71-
7263
try:
64+
# Enable SMuRF streams
65+
run.smurf.stream('on', subtype=subtype, tag=tag)
66+
7367
# Grab current telescope position
7468
resp = acu.monitor.status()
7569
az = resp.session['data']['StatusDetailed']['Azimuth current position']
@@ -110,10 +104,10 @@ def el_nod(el1, el2, num=5, pause=5):
110104
"""
111105
acu = run.CLIENTS['acu']
112106

113-
# Enable SMuRF streams
114-
run.smurf.stream('on', subtype='cal', tag='el_nods')
115-
116107
try:
108+
# Enable SMuRF streams
109+
run.smurf.stream('on', subtype='cal', tag='el_nods')
110+
117111
# Grab current telescope position
118112
resp = acu.monitor.status()
119113
init_az = resp.session['data']['StatusDetailed']['Azimuth current position']
@@ -129,4 +123,4 @@ def el_nod(el1, el2, num=5, pause=5):
129123
# Return to initial position
130124
run.acu.move_to(az=init_az, el=init_el)
131125
finally:
132-
_stop_smurfs()
126+
stop_smurfs()

src/sorunlib/stimulator.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import time
22
import sorunlib as run
3-
from sorunlib._internal import check_response
3+
from sorunlib._internal import check_response, stop_smurfs
44

55
ID_SHUTTER = 1
66

@@ -99,10 +99,7 @@ def calibrate_tau(duration_step=10,
9999

100100
time.sleep(duration_step)
101101
finally:
102-
try:
103-
run.smurf.stream('off')
104-
except RuntimeError as e:
105-
print(f"Caught error while shutting down SMuRF streams: {e}")
102+
stop_smurfs()
106103

107104
if stop:
108105
_stop()
@@ -147,10 +144,7 @@ def calibrate_gain(duration=60, speed_rpm=90,
147144
# Data taking
148145
time.sleep(duration)
149146
finally:
150-
try:
151-
run.smurf.stream('off')
152-
except RuntimeError as e:
153-
print(f"Caught error while shutting down SMuRF streams: {e}")
147+
stop_smurfs()
154148

155149
if stop:
156150
_stop()

src/sorunlib/wiregrid.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import time
22

33
import sorunlib as run
4-
from sorunlib._internal import check_response, check_running
4+
from sorunlib._internal import check_response, check_running, stop_smurfs
55

66
EL_DIFF_THRESHOLD = 0.5 # deg diff from target that its ok to run calibration
77
BORESIGHT_DIFF_THRESHOLD = 0.5 # deg
@@ -322,7 +322,7 @@ def calibrate(continuous=False, elevation_check=True, boresight_check=True,
322322
eject()
323323
finally:
324324
# Stop SMuRF streams
325-
run.smurf.stream('off')
325+
stop_smurfs()
326326

327327

328328
def time_constant(num_repeats=1):
@@ -381,7 +381,7 @@ def time_constant(num_repeats=1):
381381
insert()
382382
time.sleep(5)
383383
finally:
384-
run.smurf.stream('off')
384+
stop_smurfs()
385385

386386
for i in range(num_repeats):
387387
if current_hwp_direction == 'ccw':
@@ -404,7 +404,7 @@ def time_constant(num_repeats=1):
404404
# Run stepwise rotation
405405
rotate(continuous=False)
406406
finally:
407-
run.smurf.stream('off')
407+
stop_smurfs()
408408

409409
# Stop the HWP while streaming
410410
try:
@@ -413,7 +413,7 @@ def time_constant(num_repeats=1):
413413
run.smurf.stream('on', tag=stream_tag, subtype='cal')
414414
run.hwp.stop(active=True)
415415
finally:
416-
run.smurf.stream('off')
416+
stop_smurfs()
417417

418418
# Reverse the HWP while streaming
419419
try:
@@ -430,7 +430,7 @@ def time_constant(num_repeats=1):
430430
run.hwp.set_freq(freq=-2.0)
431431
current_hwp_direction = target_hwp_direction
432432
finally:
433-
run.smurf.stream('off')
433+
stop_smurfs()
434434

435435
# Run stepwise rotation after changing the HWP rotation
436436
try:
@@ -441,7 +441,7 @@ def time_constant(num_repeats=1):
441441
# Run stepwise rotation
442442
rotate(continuous=False)
443443
finally:
444-
run.smurf.stream('off')
444+
stop_smurfs()
445445

446446
# Bias step (the wire grid is on the window)
447447
# After changing the HWP rotation
@@ -458,7 +458,7 @@ def time_constant(num_repeats=1):
458458
eject()
459459
time.sleep(5)
460460
finally:
461-
run.smurf.stream('off')
461+
stop_smurfs()
462462

463463
# Bias step (the wire grid is off the window)
464464
bs_tag = 'wiregrid, wg_time_constant, wg_ejected, ' + \

0 commit comments

Comments
 (0)