Skip to content

Let super().end_scan() run even if the 2BM optional steps fail - #188

Open
xmap wants to merge 1 commit into
tomography:masterfrom
xmap:fix/2bm-end-scan-optional-steps
Open

Let super().end_scan() run even if the 2BM optional steps fail#188
xmap wants to merge 1 commit into
tomography:masterfrom
xmap:fix/2bm-end-scan-optional-steps

Conversation

@xmap

@xmap xmap commented Aug 21, 2026

Copy link
Copy Markdown

Companion to the fix in fix/end-scan-must-not-wedge-startscan, branched
separately from master so the two can be reviewed and merged
independently. That PR stops a raise inside end_scan() from killing the
scan thread outright. This one removes the most concrete cause of such a
raise at 2-BM: the two unguarded, best-effort steps this override adds
before calling super().end_scan().

Mechanism. TomoScan2BM.end_scan() does two things beyond the base
class's own cleanup: it appends a web camera frame to the scan file with
fid.create_dataset('exchange/web_camera_frame', data=frame), and it
copies the finished file to the analysis computer with dm.fdt_scp() or
dm.scp(). Neither block is guarded. If either raises, super().end_scan()
never runs, so ScanStatus is never set to its final value, StartScan is
never put back to 0, and scan_is_running is never cleared. This is
exactly what happened on 2026-08-20: a full disk truncated the scan file,
create_dataset raised ValueError: Unable to synchronously create dataset (address of object past end of allocation), and the scan thread died
before super().end_scan() ran.

add_theta(), called a few lines earlier in this same method, already
wraps its own hdf5 access in a bare except that logs an error and prints
a traceback, on the same reasoning: a problem writing one auxiliary dataset
should not stop the rest of end_scan() from completing. add_theta()
survived the identical failure on the identical file during the incident.
This gives the webcam-frame block and the data-transfer block the same
guard, each in its own try/except, matching add_theta()'s style and log
level (log.error plus traceback.print_exc(file=sys.stdout)).

Scope. Only tomoscan/tomoscan_2bm.py, only the end_scan() method.
The two blocks are each wrapped in a try/except; nothing inside either
block changes, and super().end_scan() is unchanged. No other method is
touched. The re-indentation needed to wrap the blocks also strips some
trailing whitespace on lines inside them; that is incidental to adding the
guards, not a separate cleanup pass.

Testing. This repo has no test coverage of end_scan(), and building
an EPICS harness for it is out of scope for this change. To reproduce:
make either block raise (for example, point the credentials file at a
missing path, or force create_dataset to fail against a truncated file)
and confirm super().end_scan() still runs and StartScan reaches 0.

end_scan() here does two things beyond the base class's own cleanup:
appends a web camera frame to the scan file, and copies the finished
file to the data analysis computer. Neither is guarded, so an
exception in either one stops super().end_scan() from ever running,
which means ScanStatus is never set to its final value, StartScan is
never put back to 0, and scan_is_running is never cleared.

add_theta(), called a few lines earlier in this same method, already
wraps its own hdf5 access in a bare except that logs and prints a
traceback, on the reasoning that a problem writing one auxiliary
dataset should not stop the rest of end_scan() from completing. The
webcam frame and the file transfer are exactly the same shape of
problem: optional, best-effort steps that write into a scan file
which may already be in a bad state. This gives each block the same
guard, so a failure in either is logged and super().end_scan() still
runs.

Untested locally: this repo has no test coverage of end_scan(), and
building an EPICS harness for it is out of scope here. To reproduce,
make either block raise (for example, point the credentials file at a
missing path, or force create_dataset to fail against a truncated
file) and confirm super().end_scan() still runs and StartScan reaches
0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant